Changeset 1171


Ignore:
Timestamp:
16/01/09 23:26:16 (3 years ago)
Author:
Paul Kienzle
Message:

xml getattrinfo now returns correct number of attrs for root; nxstest now skips bogus CDF0.0 entry in HDF4 root; nxs/napi.py now reimplements openpath so that nexus file knows its current path. Refs #149.

Location:
trunk
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/bindings/python/nxs/napi.py

    r1124 r1171  
    301301        self.filename, self.mode = filename, mode 
    302302        self.handle = c_void_p(None) 
    303         self.path = [] 
     303        self._path = [] 
     304        self._indata = False 
    304305        status = nxlib.nxiopen_(filename,mode,_ref(self.handle)) 
    305306        if status == ERROR: 
     
    311312        self.isopen = True 
    312313 
     314    def _getpath(self):  
     315        return '/'+'/'.join(self._path) 
     316    path = property(_getpath,doc="Unix-style path to node") 
     317 
    313318    def __del__(self): 
    314319        """ 
     
    341346        if status == ERROR: 
    342347            raise NeXusError, "Could not open %s"%(self.filename) 
    343         self.path = [] 
     348        self._path = [] 
     349        self._indata = False 
    344350 
    345351    nxlib.nxiclose_.restype = c_int 
     
    358364            if status == ERROR: 
    359365                raise NeXusError, "Could not close NeXus file %s"%(self.filename) 
    360         self.path = [] 
     366        self._path = [] 
     367        self._indata = False 
    361368 
    362369    nxlib.nxiflush_.restype = c_int 
     
    412419        """ 
    413420        Open a particular group '/path/to/group'.  Paths can 
    414         be relative to the currently open group. 
     421        be absolute or relative to the currently open group. 
     422        If openpath fails, then currently open path may not 
     423        be different from the starting path. 
    415424 
    416425        Raises ValueError. 
     
    418427        Corresponds to NXopenpath(handle, path) 
    419428        """ 
    420         status = nxlib.nxiopenpath_(self.handle, path) 
    421         if status == ERROR: 
    422             raise ValueError, "Could not open %s in %s"%(path,self._loc()) 
    423         n,path,nxclass = self.getgroupinfo() 
    424         if path != 'root': 
    425             self.path = path.split('/') 
     429        self._openpath(path, opendata=True) 
     430 
     431    def _openpath(self, path, opendata=True): 
     432        """helper function: open relative path and maybe data""" 
     433        # Determine target node as sequence of group names 
     434        if path == '/': 
     435            target = [] 
     436        elif path.startswith('/'): 
     437            target = path[1:].split('/') 
    426438        else: 
    427             self.path = [] 
    428  
     439            target = self._path + path.split('/') 
     440 
     441        # Remove relative path indicators from target 
     442        L = [] 
     443        for t in target: 
     444            if t == '.':  
     445                # Skip current node 
     446                pass 
     447            elif t == '..': 
     448                if L == []: 
     449                    raise ValueError("too many '..' in path") 
     450                L.pop() 
     451            else: 
     452                L.append(t) 
     453        target = L 
     454        #print "current path",self._path 
     455        #print "%s"%path,target 
     456 
     457        # Find which groups need to be closed and opened 
     458        up = [] 
     459        down = [] 
     460        for i,name in enumerate(target): 
     461            if i == len(self._path): 
     462                #print "target longer than current" 
     463                up = [] 
     464                down = target[i:] 
     465                break 
     466            elif self._path[i] != name: 
     467                #print "target and current differ at",name 
     468                up = self._path[i:] 
     469                down = target[i:] 
     470                break 
     471        else: 
     472            #print "target shorter than current" 
     473            up = self._path[len(target):] 
     474            down = [] 
     475        up.reverse() 
     476        #print "close,open",up,down 
     477 
     478        # Close groups on the way up 
     479        if self._indata and up != []: 
     480            self.closedata() 
     481            up.pop() 
     482        for target in up: 
     483            self.closegroup() 
     484         
     485        # Open groups on the way down 
     486        for target in down: 
     487            # Find target name in current group.  We need to do this because 
     488            # we can't open the group without knowing the class.  We also 
     489            # need the class so that we can handle SDS specially. 
     490            n,_,_ = self.getgroupinfo() 
     491            self.initgroupdir() 
     492            for i in range(n): 
     493                name,nxclass = self.getnextentry() 
     494                if name != target: continue 
     495                if nxclass != 'SDS': 
     496                    self.opengroup(name,nxclass) 
     497                elif opendata:  
     498                    self.opendata(name) 
     499                break 
     500            else: 
     501                raise ValueError("node %s not in %s"%(name,self.path)) 
    429502 
    430503    nxlib.nxiopengrouppath_.restype = c_int 
     
    440513        Corresponds to NXopengrouppath(handle, path) 
    441514        """ 
    442         status = nxlib.nxiopengrouppath_(self.handle, path) 
    443         if status == ERROR: 
    444             raise ValueError, "Could not open %s in %s"%(path,self.filename) 
    445         n,path,nxclass = self.getgroupinfo() 
    446         if path != 'root': 
    447             self.path = path.split('/') 
    448         else: 
    449             self.path = [] 
    450  
     515        self._openpath(path,opendata=False) 
    451516 
    452517    nxlib.nxiopengroup_.restype = c_int 
     
    465530            raise ValueError,\ 
    466531                "Could not open %s:%s in %s"%(nxclass,name,self._loc()) 
    467         self.path.append(name) 
     532        self._path.append(name) 
    468533 
    469534    nxlib.nxiclosegroup_.restype = c_int 
     
    479544        #print "close group" 
    480545        status = nxlib.nxiclosegroup_(self.handle) 
    481         group = self.path.pop() 
    482         if status == ERROR: 
    483             raise NeXusError, "Could not close %s:"%(group,self._loc()) 
    484  
    485     nxlib.nxigetinfo_.restype = c_int 
    486     nxlib.nxigetinfo_.argtypes = [c_void_p, c_int_p, c_char_p, c_char_p] 
     546        if status == ERROR: 
     547            raise NeXusError, "Could not close group at %s"%(name,self._loc()) 
     548        self._path.pop() 
     549 
     550    nxlib.nxigetgroupinfo_.restype = c_int 
     551    nxlib.nxigetgroupinfo_.argtypes = [c_void_p, c_int_p, c_char_p, c_char_p] 
    487552    def getgroupinfo(self): 
    488553        """ 
    489554        Query the currently open group returning the tuple 
    490         numentries, path, nxclass.  The path consists of names 
    491         of subgroups starting at the root separated by "/". 
     555        numentries, name, nxclass. 
    492556 
    493557        Raises ValueError if the group could not be opened. 
    494558 
    495559        Corresponds to NXgetgroupinfo(handle) 
     560 
     561        Note: corrects error in HDF5 where getgroupinfo returns the entire 
     562        path rather than the group name.  Use the path attribute to get 
     563        a sensible value of path. 
    496564        """ 
    497565        # Space for the returned strings 
     
    503571            raise ValueError, "Could not get group info: %s"%(self._loc()) 
    504572        #print "group info",nxclass.value,name.value,n.value 
    505         return n.value,path.value,nxclass.value 
     573        name = path.value.split('/')[-1]  # Protect against HDF5 returning path 
     574        return n.value,name,nxclass.value 
    506575 
    507576    nxlib.nxiinitgroupdir_.restype = c_int 
     
    566635        # first, then process the entries one by one.  Keep track 
    567636        # of the path so we can restore it between entries. 
    568         n,path,_ = self.getgroupinfo() 
    569         #print "path",path 
    570         if not path == "root": 
    571             path = "/"+path 
    572         else: 
    573             path = "/" 
     637        path = self.path 
    574638 
    575639        # Read list of entries 
    576640        self.initgroupdir() 
     641        n,_,_ = self.getgroupinfo() 
    577642        L = [] 
    578643        for i in range(n): 
     
    634699        if status == ERROR: 
    635700            raise ValueError, "Could not open data %s: %s"%(name, self._loc()) 
    636         self.path.append(name) 
     701        self._path.append(name) 
     702        self._indata = True 
    637703 
    638704    nxlib.nxiclosedata_.restype = c_int 
     
    649715        #print "closing data" 
    650716        status = nxlib.nxiclosedata_(self.handle) 
    651         name = self.path.pop() 
    652717        if status == ERROR: 
    653718            raise NeXusError,\ 
    654                 "Could not close data %s: %s"%(name,self._loc()) 
     719                "Could not close data at %s"%(name,self._loc()) 
     720        self._path.pop() 
     721        self._indata = False 
    655722 
    656723    nxlib.nximakedata_.restype = c_int 
     
    881948        Corresponds to NXgetattr(handle,name,data,&length,&storage) 
    882949        """ 
     950        if dtype is 'char': length += 1  # HDF4 needs zero-terminator 
    883951        datafn,pdata,size = self._poutput(str(dtype),[length]) 
    884952        storage = c_int(_nxtype_code[str(dtype)]) 
     
    10651133        combines the work of attrinfo/initattrdir/getnextattr/getattr. 
    10661134        """ 
    1067         # To preserve the semantics we must read in the whole list 
    1068         # first, then process the entries one by one. 
    1069         pathstr = "/"+"/".join(self.path) 
    1070         #print "checking for links from",pathstr 
    10711135        n = self.getattrinfo() 
    10721136        self.initattrdir() 
     
    10751139            if name == "target": 
    10761140                target = self.getattr(name,length,dtype) 
    1077                 #print "target %s, path %s"%(target,pathstr) 
    1078                 if target != pathstr: 
     1141                #print "target %s, path %s"%(target,self.path) 
     1142                if target != self.path: 
    10791143                    return target 
    10801144                else: 
     
    11421206    def _loc(self): 
    11431207        """ 
    1144         Return file location as string filename:path 
     1208        Return file location as string filename(path) 
    11451209 
    11461210        This is an extension to the NeXus API. 
    11471211        """ 
    1148         if not self.path == []: 
    1149             pathstr = "/".join(self.path) 
    1150         else: 
    1151             pathstr = "root" 
    1152         return "%s(%s)"%(self.filename,pathstr) 
     1212        return "%s(%s)"%(self.filename,self.path) 
    11531213 
    11541214    def _poutput(self, dtype, shape): 
     
    12241284        TODO: Break this into a tree walker and a visitor. 
    12251285        """ 
    1226         oldpath = "/"+"/".join(self.path) 
    1227         if not path: path = oldpath 
     1286        oldpath = self.path 
    12281287        self.openpath(path) 
    12291288 
  • trunk/bindings/python/nxstest.py

    r1170 r1171  
    4545        print "%(prefix)s@%(attr)s: %(value)s" % locals() 
    4646    for name,nxclass in file.entries(): 
     47        if nxclass.startswith("CDF"): continue # Root has an extra CDF class 
    4748        if nxclass == "SDS": 
    4849            shape,dtype = file.getinfo() 
     
    189190    file = nxs.open(filename,'rw') 
    190191    if filename != file.inquirefile(): fail("Files don't match") 
    191     attrs = file.getattrinfo() 
    192     if attrs != 4: fail("Expected 4 root attributes but got %d", attrs) 
    193     for i in range(attrs): 
     192 
     193    # check headers 
     194    num_attrs = file.getattrinfo() 
     195    wxattrs = ['xmlns','xmlns:xsi','xsi:schemaLocation', 'XML_version'] 
     196    w4attrs = ['HDF_version'] 
     197    w5attrs = ['HDF5_Version'] 
     198    extras = dict(wx=wxattrs,w4=w4attrs,w5=w5attrs) 
     199    expected_attrs = ['NeXus_version','file_name','file_time']+extras[mode] 
     200    for i in range(num_attrs): 
    194201        name,dims,type = file.getnextattr() 
    195         if name not in ['file_time','HDF_version','HDF5_Version','XML_version', 
    196                         'NeXus_version','file_name']: 
     202        if name not in expected_attrs: 
    197203            fail("attribute %s unexpected"%(name)) 
     204    if num_attrs != len(expected_attrs):  
     205        fail("Expected %d root attributes but got %d" 
     206             % (len(expected_attrs),num_attrs)) 
    198207     
    199208    file.opengroup('entry','NXentry') 
     
    230239    if not get == numpy.int32(42): fail("i4_attribute retrieved %s"%(get)) 
    231240    get = file.getattr("r4_attribute",1,'float32') 
    232     if not get == numpy.float32(3.14159265): fail("r4_attribute retrieved %s"%(get)) 
     241    if ((mode=='wx' and not abs(get-3.14159265) < 1e-6) or 
     242        (mode!='wx' and not get == numpy.float32(3.14159265))): 
     243        fail("r4_attribute retrieved %s"%(get)) 
    233244    ## Oops... NAPI doesn't support array attributes 
    234245    #expect = numpy.array([3,2],dtype='int32') 
  • trunk/src/nxxml.c

    r1104 r1171  
    16661666  pXMLNexus xmlHandle = NULL; 
    16671667  mxml_node_t *current = NULL; 
    1668   int stackPtr, currentAtt; 
     1668  int stackPtr, currentAtt, skip; 
    16691669 
    16701670  xmlHandle = (pXMLNexus)fid; 
     
    16781678    hide type and group name attributes 
    16791679  */ 
    1680   if(!isDataNode(current)) { 
    1681     *iN = current->value.element.num_attrs -1; 
    1682     return NX_OK; 
    1683   } 
    1684   if(mxmlElementGetAttr(current,TYPENAME) != NULL){ 
    1685     *iN = current->value.element.num_attrs -1; 
     1680  skip=0; 
     1681  if(isDataNode(current)) { 
     1682    /* data nodes may have type */ 
     1683    if(mxmlElementGetAttr(current,TYPENAME) != NULL) skip=1; 
    16861684  } else { 
    1687     *iN = current->value.element.num_attrs; 
    1688   } 
     1685    /* group nodes (except root) have name */ 
     1686    if(mxmlElementGetAttr(current,"name") != NULL) skip=1; 
     1687  } 
     1688  *iN = current->value.element.num_attrs - skip; 
    16891689  return NX_OK; 
    16901690} 
Note: See TracChangeset for help on using the changeset viewer.