#!/opt/conda/conda-bld/pyciao_1701809863847/_h_env_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placehold_placeh/bin/python3
# 
#  Copyright (C) 2010-2013,2015-2018,2020-2021,2023  Smithsonian Astrophysical Observatory
#
#
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 3 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License along
#  with this program; if not, write to the Free Software Foundation, Inc.,
#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#

from __future__ import print_function

from cxcdm import *
from cxcdm._cxcdm import _dmSetVerbose

from region import *

import numpy as np
import sys
import os
import subprocess

class TestCXCDM:
    """
    Class to test the python cxcdm module.
    Arguments:
        indir   (optional)  <path>
          Directory containing input files
          default = "./" or  Environment variable 'TESTIN'
        outdir  (optional)  <path>
          Directory to write output files
          default = "./" or Environment variable 'TESTOUT'
        basedir (optional)  <path>
          Directory containing baseline files for comparison
          default = "./" or Environment variable 'TESTSAV'
        tests   (optional)  [list]
          List of test #s to run
          default = all tests
        log     (optional)  <True|False>
          Flag to control log file generation.
          True  = generate log as "<outdir>/cxcdm_verbose.txt"
          False = no log, output goes to stdout
        chklog  (optional)  <True|False>
          Flag to control log file comparison.
          True  = verify log file.
          False = do not verify log file.
    """

    def __init__(self, *args):
        self.indir  = "./"
        self.outdir = "./"
        self.basdir = "./"
        self.fh     = sys.stdout
        self._log   = False
        self._chklog= True

        # set format datatype for astype() function, to display string data
        # unifies P2 and P3 output
        if sys.version_info[0] < 3:
            self._stype = "S"
        else:
            self._stype = "U"


        self.ntests = 12
        self.nunit  = 30
        self.tests  = list(range(1,self.ntests+1))+list(range(101,101+self.nunit))
        self.infiles = ["testm000000000_in1.fits",
                        "testm000000000_in1.fits[IMGONE]",
                        "dt002m009.fits",
                        "dt002m009.fits[GTI9]",
                        "dt002m009.fits[GTI5]",
                        "testm000000000_in3.fits",
                        "testm000000000_in4.fits",
                        "testm000000000_in5.fits",
                        "indt035m013.fits" ]

        self.outfiles = ["testm000000000_out1.fits",
                         "testm000000000_out2.fits",
                         "testm000000000_out3.fits",  
                         "testm000000000_out4.fits",
                         "testm000000000_out5.fits",
                         "testm000000000_out6.fits",
                         "testm000000000_out7.fits",
                         "testm000000000_out8.fits",
                         "testm000000000_out9.fits",
                         "testm000000000_out10.fits",
                         "testm000000000_out11.fits",
                         "testm000000000_out12.fits",
                         "testm000000000_out13.fits",
                         "testm000000000_out14.fits",
                         "testm000000000_out15.fits",
                         "testm000000000_out16.fits",
                         "testm000000000_out17.fits",
                         "testm000000000_out18.fits",
                         "testm000000000_out19.fits", 
                         "testm000000000_out20.fits", 
                         "testm000000000_out21.txt" ]

        # Check for environment variable directory defaults
        if 'TESTIN' in os.environ:
            self.indir = os.environ['TESTIN']
            self.indir += "/pycxcdm"

        if 'TESTOUT' in os.environ:
            self.outdir = os.environ['TESTOUT']
            self.outdir += "/pycxcdm"

        if 'TESTSAV' in os.environ:
            self.basdir = os.environ['TESTSAV']
            self.basdir += "/pycxcdm"

        cnt = 0
        # Parse and process any arguments
        for item in args:
            if item.count('=') == 1:
                (key,val)=item.split('=')
                if key == 'indir':
                    self.indir = val
                elif key == 'outdir':
                    self.outdir = val
                elif key == 'basdir':
                    self.basdir = val
                elif key == 'tests':
                    tlist = val.split(',')
                    self.tests = [ int(tnum) for tnum in tlist ]
                elif key == 'log':
                    if val == 'True':
                        self._log = True
                    else:
                        self._log = False
                elif key == 'checklog':
                    if val == 'True':
                        self._chklog = True
                    else:
                        self._chklog = False
                else:
                    raise TypeError ("TestCXCDM() got an unexpected keyword argument '%s'" % key)
            else:
                if cnt == 0:
                    self.indir = item
                elif cnt == 1:
                    self.outdir = item
                elif cnt == 2:
                    self.basdir = item
                elif cnt == 3:
                    tlist = item.split(',')
                    self.tests = [ int(tnum) for tnum in tlist ]
                elif cnt == 4:
                    if item == 'True':
                        self._log = True
                    else:
                        self._log = False

            cnt = cnt + 1

        if not self.indir.endswith('/'):
            self.indir = self.indir + '/'
        if not self.outdir.endswith('/'):
            self.outdir = self.outdir + '/'
        if not self.basdir.endswith('/'):
            self.basdir = self.basdir + '/'

        # Add test bin to PATH for output comparison
        path = os.environ['PATH']
        testbin = os.environ['ASCDS_INSTALL'] + "/test/bin/datamodel"
        os.environ['PATH'] = path + ":" + testbin
        path = os.environ['PATH']

        # Clean up existing output files
        self.cleanup()


    def __repr__(self):
        buf =  "CXCDM Test Suite:\n"
        buf += "---------------- \n"
        buf += "   Indir  = %s\n" % self.indir
        buf += "   Outdir = %s\n" % self.outdir
        buf += "   Basdir = %s\n" % self.basdir
        buf += "   NTests = %d\n" % len(self.tests)
        buf += "\n"
        return buf

    def _check_datatype(self, result, expected ):
        retval = False
        if not isinstance( result, expected ):
            print( 'TypeError, expected type '+str(expected)+' found '+str(type(result)), file=self.fh)
        else:
            retval = True
        return retval

    def _check_value(self, result, expected ):
        retval = False
        if result != expected :
            print( 'ValueError, expected '+str(expected)+' found '+str(result), file=self.fh)
        else:
            retval = True
        return retval

    def _get_dtype_string(self, dtype ):
        if dtype is np.string_ :
            result = "numpy.string_"
        elif dtype is np.uint8 :
            result = "numpy.uint8"
        elif dtype is np.uint16 :
            result = "numpy.uint16"
        elif dtype is np.uint64 :
            result = "numpy.uint64"
        elif dtype is np.int16 :
            result = "numpy.int16"
        elif dtype is np.int64 :
            result = "numpy.int64"
        elif dtype is np.float32 :
            result = "numpy.float32"
        elif dtype is np.float64 :
            result = "numpy.float64"
        elif dtype is np.bool_ :
            result = "numpy.bool_"
        else:
            result = "TypeError, unrecognized dtype "+str(dtype)

        return result

    def cleanup(self):
        """
        Delete output files from 'outdir' if present.
        """

        if os.path.exists( self.outdir ):
            for file in self.outfiles:
                path = self.outdir + file
                if os.path.isfile( path ):
                    os.system("rm " + path)
        else:
            os.system("mkdir " + self.outdir)
            


    def run(self):
        """
        Loop over tests to execute and run them.
        Report PASS|FAIL for each test.
        Returns overall grade for tests run (PASS|FAIL)
        """
        anybad = False

        # Open Log file for verbose output
        if self._log == True:
            file = self.outdir + "cxcdm_verbose.txt"
            self.fh = open( file, 'w')
            print("Running Tests..")

        for ii in self.tests:
            try:
                exec ('self.test_%d ()'%ii)

            except Exception as e:
                print("  ", e)
                grade = "FAIL"
                anybad = True
            else:
                grade = "PASS"
            
            print("  test_%d: %s" % (ii,grade))
            if not self._log:
                print() 
                
        if self._log == True:
            self.fh.close()

        if anybad:
            return "FAIL"
        else:
            return "PASS"


    def check_file(self, file ):
        """
        Will find matching file in 'basedir' and compare.
          file = full path to file being checked

        Returns True if OK, False otherwise
        """
        result = False
        tfile  = self.outdir + "tmp.txt"

        # check specified file exists
        if os.path.isfile( file ):
            fname = os.path.basename( file )
            basefile = self.basdir + fname
        else:
            raise IOError("check_file(): Specified file does not exist %s" % file)

        print("Checking file: %s" % fname)
        
        # convert provided file to ASCII DTF format
        tfile1 = self.outdir + "tmp_new.dtf"
        comstr = "dmtcopy infile=%s outfile=%s'[opt kernel=text/dtf]' opt=all clobber=yes" % (file, tfile1)
        if os.system( comstr ):
            raise RuntimeError("check_file(): Problem converting file for comparison %s" % file)

        # convert baseline file to ASCII DTF format
        tfile2 = self.outdir + "tmp_bas.dtf"
        comstr = "dmtcopy infile=%s outfile=%s'[opt kernel=text/dtf]' opt=all clobber=yes" % (basefile, tfile2)
        if os.system( comstr ):
            raise RuntimeError("check_file(): Problem converting file for comparison %s" % basefile)

        # filter out stuff that changes.
        comstr = "cat %s | egrep -v \"ASCDSVER|CHECKSUM|DATASUM|HISTORY|HISTNUM\" > %s ; mv %s %s" % ( tfile1, tfile, tfile, tfile1 )
        os.system( comstr )
        comstr = "cat %s | egrep -v \"ASCDSVER|CHECKSUM|DATASUM|HISTORY|HISTNUM\" > %s ; mv %s %s" % ( tfile2, tfile, tfile, tfile2 )
        os.system( comstr )

        # compare the ascii files.
        comstr = "diff %s %s > /dev/null" % (tfile1, tfile2)
        if os.system( comstr ):
            result = False
        else:
            result = True

        if os.path.isfile( tfile1 ):
            os.system("rm " + tfile1 )
        if os.path.isfile( tfile2 ):
            os.system("rm " + tfile2 )

        if result == True:
            print("   OK")
        else:
            print("   Problem")

        return result


    def check_log(self):
        """
        Will compare log file ( if appropriate ) against the baseline version.
        Returns True if OK, False otherwise
        """
        result = False

        file     = self.outdir + "cxcdm_verbose.txt"
        basefile = self.basdir + "cxcdm_verbose.txt"

        print("Checking log file:")
        if self._log:
            if len(self.tests) == (self.ntests + self.nunit):
                if os.path.isfile( file ):
                    comstr = "diff %s %s > /dev/null" % (file, basefile)
                    if os.system( comstr ):
                        result = False
                    else:
                        result = True
            else:
                print("  Subset of tests run, unable to compare log")
                result = True
        else:
            print("  No log generated.")
            result = True

        if result == True:
            print("   OK")
        else:
            print("   Problem")

        return result


    def verify(self):
        """
        Determine which output files are expected from the tests executed,
        and compare them against their corresponding 'baseline' versions.
        If all tests were run, and log file generated, it will also be compared
        against the 'baseline'.

        Returns PASS|FAIL indicating whether or not any file shows differences.
           'FAIL' = one or more file has differences
           'PASS' = all file compare without differences.
        """
        anybad = False

        print("")
        print("Verify Outputs")

        flist = []

        # make list of output files we should expect to have been created
        if self.tests.count(6) == 1:
            flist.append(self.outdir + self.outfiles[0])
            flist.append(self.outdir + self.outfiles[3])
        if (self.tests.count(5) == 1):
            flist.append(self.outdir + self.outfiles[1])
        if self.tests.count(7) == 1:
            flist.append(self.outdir + self.outfiles[2])
        if self.tests.count(8) == 1:
            flist.append(self.outdir + self.outfiles[4])
        if self.tests.count(9) == 1:
            flist.append(self.outdir + self.outfiles[5])
        if self.tests.count(10) == 1:
            flist.append(self.outdir + self.outfiles[6])
        if self.tests.count(11) == 1:
            flist.append(self.outdir + self.outfiles[7])
            flist.append(self.outdir + self.outfiles[12])
        if self.tests.count(12) == 1:
            flist.append(self.outdir + self.outfiles[8])
        if self.tests.count(123) == 1:
            flist.append(self.outdir + self.outfiles[9])
        if self.tests.count(124) == 1:
            flist.append(self.outdir + self.outfiles[10])
        if self.tests.count(126) == 1:
            flist.append(self.outdir + self.outfiles[11])
        if self.tests.count(127) == 1:
            flist.append(self.outdir + self.outfiles[13])
        if self.tests.count(128) == 1:
            flist.append(self.outdir + self.outfiles[14])
            flist.append(self.outdir + self.outfiles[15])
            flist.append(self.outdir + self.outfiles[16])
        if self.tests.count(129) == 1:
            flist.append(self.outdir + self.outfiles[17])

        if len(flist) == 0:
            print("  Test set generates no files")

        # compare output files
        for file in flist:
            try:
                if self.check_file( file ) == False:
                    anybad = True
            except RuntimeError as e:
                print("  ", e)
                anybad = True
                pass

        # check log file
        if self._chklog == True:
            if self.check_log() == False:
                anybad = True
        
        if anybad:
            return "FAIL"
        else:
            return "PASS"


    # ----------------------------------------------------------------------
    # Dataset Basic Read
    # ----------------------------------------------------------------------
    def test_1( self ):
        """
        dmDataset
          dmDatasetAccess 
          dmDatasetOpen
          dmDatasetWriteable
          dmDatasetGetName
          dmDatasetGetNoBlocks
          dmDatasetGetCurrentBlockNo
          dmDatasetGetBlockName
          dmDatasetGetBlockType
          dmDatasetClose

          dmDatasetPrint
        """
        print("Running Test 1", file=self.fh)

        # Assign input/output file names
        infile = self.indir + self.infiles[0]

        try:
            dmDatasetAccess("", "RW")
        except ValueError as e:
            print("", file=self.fh)
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass

        try:
            dmDatasetAccess(infile, "w")
        except ValueError as e:
            print("", file=self.fh)
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass

        if sys.version_info[0] < 3:
            print("dmDatasetAccess('%s','RW') = %s" %(infile, dmDatasetAccess( bytes(infile), b"RW") ), file=self.fh);
        else:
            print("dmDatasetAccess('%s','RW') = %s" %(infile, dmDatasetAccess( bytes(infile, "utf-8"), b"RW" )), file=self.fh);
            

        print("dmDatasetAccess('%s/doesNotExist.fits','RW') = %s" %(self.indir, dmDatasetAccess( self.indir+"doesNotExist.fits", "RW" )), file=self.fh);

        try:
            ds = dmDatasetOpen( infile )
        except:
            raise

        try:
            if dmDatasetWriteable( ds ):
                mode = 'Write'
            else:
                mode = 'Read Only'
        except:
            raise
        
        try:
            dsname = dmDatasetGetName( ds )
        except:
            raise

        try:
            nblocks = dmDatasetGetNoBlocks( ds )
        except:
            raise

        try:
            curblock = dmDatasetGetCurrentBlockNo(ds)
        except:
            raise


        # Note: dmDatasetPrint uses dmDatasetGetBlockName, dmDatasetGetBlockType.
        print(dmDatasetPrint( ds ), file=self.fh);
        
        try:
            dmDatasetClose( ds )
        except:
            raise


    # ----------------------------------------------------------------------
    # Block Read
    # ----------------------------------------------------------------------
    def test_2( self ):
        """
        Dataset
          dmDatasetClose
          dmDatasetGetName
          dmDatasetGetNoBlocks
          dmDatasetMoveToBlock
          dmDatasetNextBlock
          dmDatasetWriteable
        Block
          dmBlockOpen(file)
          dmBlockGetDataset
          dmBlockGetName
          dmBlockGetNo
          dmBlockGetType
          dmBlockClose
        """
        
        print("Running Test 2", file=self.fh)

        # Assign input/output file names
        infile = self.indir + self.infiles[0]

        try:
            b = dmBlockOpen( infile )
        except:
            raise

        try:
            curblock = dmBlockGetNo( b )
        except:
            raise

        try:
            ds = dmBlockGetDataset( b )
        except:
            raise

        try:
            if dmDatasetWriteable( ds ):
                mode = 'Write'
            else:
                mode = 'Read Only'
        except:
            raise
        
        try:            
            dsname = dmDatasetGetName( ds )
        except:
            raise

        try:
            nblocks = dmDatasetGetNoBlocks( ds )
        except:
            raise

        try:
            b = dmDatasetMoveToBlock( ds, 1 )
        except:
            raise
        
        print("  ----------------------------------------------------------------------", file=self.fh)
        print("  Dataset: %s" % dsname, file=self.fh)
        print("        mode = %s" % mode, file=self.fh)
        print("     nblocks = %d" % nblocks, file=self.fh)
        print("     default = %d" % curblock, file=self.fh)
        print("  ----------------------------------------------------------------------", file=self.fh)
        print("       Block  Name                Type                                  ", file=self.fh)
        print("  ----------------------------------------------------------------------", file=self.fh)
        
        for ii in range(1,nblocks+1):
            try:
                bnum  = dmBlockGetNo( b )
                bname = dmBlockGetName( b )
                btype = dmBlockGetType( b )
            except:
                raise
            print("  Block %4d: %-20s %-10s" % (bnum, bname, btype), file=self.fh)

            try:
                dmBlockClose(b)
                del b
            except:
                raise

            try:
                if ii < nblocks:
                    b = dmDatasetNextBlock(ds)
            except:
                raise

        print("", file=self.fh)

        try:
            dmDatasetClose( ds )
        except:
            raise



    # ----------------------------------------------------------------------
    # Table Block Read
    # ----------------------------------------------------------------------
    def test_3( self ):
        """
        Block
          dmBlockGetKeyList
          dmBlockReadComment              
          dmTableClose
          dmTableGetNoRows
          dmTableGetNoCols
          dmTableOpen
          dmTableOpenColumnList
          
        Descriptor
          dmGetArrayDim
          dmGetArrayDimensions
          dmGetArraySize
          dmGetCpt
          dmGetCptName              
          dmGetDataType
          dmGetDesc
          dmGetDisp                  # NOT IMPLEMENTED
          dmGetElementDim
          dmGetName
          dmGetUnit
          dmDescriptorGetCoord
          dmDescriptorGetLength
          dmDescriptorGetNo
          dmDescriptorGetNoCoords
          dmDescriptorGetType        # NOT IMPLEMENTED
          dmDescriptorGetRange
          dmDescriptorIsVarLength    
        """
        
        print("Running Test 3", file=self.fh)

        # Assign input/output file names
        infile = self.indir + self.infiles[0]

        # Open input file
        try:
            b = dmTableOpen( infile )
        except:
            raise

        print("-------------------------------", file=self.fh)
        print("Block    N: %-30s Table   %7ld cols x %-7ld rows" % (dmBlockGetName(b), dmTableGetNoCols(b), dmTableGetNoRows(b) ), file=self.fh)
        print("-------------------------------", file=self.fh)
        print("", file=self.fh)


        # Extract key list
        keys = dmBlockGetKeyList( b )

        # Display Key info
        print("--------------------------------------------------------------------------------", file=self.fh)
        print("Header keys for block %s" % dmBlockGetName( b ), file=self.fh)
        print("--------------------------------------------------------------------------------", file=self.fh)
        print("       Name            Unit       Type            Description", file=self.fh)
        for key in keys:
            name  = dmGetName( key )
            unit  = dmGetUnit( key )
            dtype = self._get_dtype_string( dmGetDataType( key ) )
            desc  = dmGetDesc( key )
            
            print("       %-15s %-10s %-15s %-25s" % (name, unit, dtype, desc), file=self.fh)

        # get comment/history if any
        print("--------------------------------------------------------------------------------", file=self.fh)
        print("Header Comments/History for Table Block %s" % dmBlockGetName( b ), file=self.fh)
        print("--------------------------------------------------------------------------------", file=self.fh)
        print("  Key    Tag        Value", file=self.fh)
        for x in range(1, dmBlockGetNoKeys(b)+1):  
            dmBlockMoveToKey(b, x) 
            done = False
            while (not done):
                (tag, cmt) = dmBlockReadComment( b )
                if tag is None:
                    done = True 
                else:
                    print(" %2d      %s  %s" % (x, tag, cmt), file=self.fh)

        # Extract Column list
        cols = dmTableOpenColumnList( b )

        # Display Column info
        print("", file=self.fh)
        print("--------------------------------------------------------------------------------", file=self.fh)
        print("Columns for Table Block %s" % dmBlockGetName( b ), file=self.fh)
        print("--------------------------------------------------------------------------------", file=self.fh)
        print("ColNo  Name                 Unit        Type           Shape       Range              Description", file=self.fh)

        for dd in cols:
            name  = dmGetName( dd )
            unit  = dmGetUnit( dd )
            dtype = self._get_dtype_string( dmGetDataType( dd ) )
            if dtype.find("string_" ):
                dtype = dtype.replace("string_", "S%ld" % dmDescriptorGetLength(dd) )
            desc  = dmGetDesc( dd )

            vdim = dmGetElementDim(dd)
            if vdim > 1:
                cptnames = []
                for ii in range (1,vdim+1):
                    cpt = dmGetCpt(dd, ii )
                    tmpstr = dmGetName( cpt )
                    if (tmpstr != dmGetCptName( dd, ii ) ):  
                       tmpstr = "PROBLEM"
                    cptnames.append( tmpstr )
                name = name + "(" + ",".join(cptnames) + ")"
                vc = dd

            shape = ""
            ndim = dmGetArrayDim(dd)
            if ndim > 0:
                dims = dmGetArrayDimensions(dd)
                if ( dims.prod() != dmGetArraySize(dd) ):
                    shape = "PROBLEM"
                else:
                    shape = str(dims)


            if ( dmDescriptorIsVarLength(dd) == True ):
                shape = shape + " var"

            rng = ""
            try:
                (rngmin,rngmax) = dmDescriptorGetRange(dd)
                rng = self.test_format_range( rngmin, rngmax )
            except RuntimeError as e:
                print(e)
                raise

            colno = dmDescriptorGetNo(dd)
            print("%5d  %-20s %-10s %-15s  %5s        %-15s   %-25s" % (colno, name, unit, dtype, shape, rng, desc), file=self.fh)


        # get cpt errs for incorrect comp numbers  
        print("", file=self.fh)
        print("testing dmGetCptName... ", file=self.fh)
        try:
            dmGetCptName(vc, 0)
        except ValueError as e:
            print("", file=self.fh)
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass

        try:
            dmGetCptName(vc, dmGetElementDim(vc)+1)
        except ValueError as e:
            print("", file=self.fh)
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass

        try:
            dmGetCptName(vc)
        except TypeError as e:
            print("", file=self.fh)
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            print("", file=self.fh)
            pass

        # Display Coord info
        print("", file=self.fh)
        print("--------------------------------------------------------------------------------", file=self.fh)
        print("Coordinates for Table Block %s" % dmBlockGetName( b ), file=self.fh)
        print("--------------------------------------------------------------------------------", file=self.fh)
        print("ColNo  Name                 Description", file=self.fh)

        for dd in cols:
            colno = dmDescriptorGetNo(dd)
            ncoords = dmDescriptorGetNoCoords( dd )
            for ii in range  (1,ncoords+1):
                cdd = dmDescriptorGetCoord(dd, ii)
                name  = dmGetName( cdd )
                desc  = dmGetDesc( cdd )

                print("%5d  %-20s %-25s" % (colno, name, desc), file=self.fh)



        # Close input file and dataset
        try:
            dmTableClose( b )
        except:
            raise

    # ----------------------------------------------------------------------
    # Image Block Read
    # ----------------------------------------------------------------------
    def test_4( self ):
        """
        Block
          dmBlockGetKeyList
          dmImageClose             
          dmImageGetDataDescriptor
          dmImageOpen
          
        Descriptor
          dmArrayGetAxisGroup
          dmArrayGetNoAxisGroups
          dmGetArrayDim
          dmGetArrayDimensions
          dmGetArraySize
          dmGetCpt                 # NOT IMPLEMENTED
          dmGetCptName             
          dmGetDataType
          dmGetDesc
          dmGetDisp                # NOT IMPLEMENTED
          dmGetElementDim          # NOT IMPLEMENTED*
          dmGetName
          dmGetUnit
          dmDescriptorGetCoord
          dmDescriptorGetNo        # NOT IMPLEMENTED
          dmDescriptorGetNoCoords
          dmDescriptorGetType      # NOT IMPLEMENTED
          dmDescriptorGetRange
          dmDescriptorIsVarLength  
        """
        
        print("Running Test 4", file=self.fh)

        # Assign input/output file names
        infile  = self.indir + self.infiles[1]

        # open the Image 
        try:
            b = dmImageOpen( infile )
        except:
            raise

        # Extract key list
        keys = dmBlockGetKeyList( b )

        # Display Key info
        print("--------------------------------------------------------------------------------", file=self.fh)
        print("Header keys for block %s" % dmBlockGetName( b ), file=self.fh)
        print("--------------------------------------------------------------------------------", file=self.fh)
        print("       Name            Unit       Type            Description", file=self.fh)
        for key in keys:
            name  = dmGetName( key )
            unit  = dmGetUnit( key )
            if unit != "":
                unit = "[" + unit + "]"
            dtype = self._get_dtype_string( dmGetDataType( key ) )
            desc  = dmGetDesc( key )
            
            print("       %-15s %-10s %-15s %-25s" % (name, unit, dtype, desc), file=self.fh)


        # Display Column info
        print("", file=self.fh)
        print("--------------------------------------------------------------------------------", file=self.fh)
        print("Columns for Image Block %s" % dmBlockGetName( b ), file=self.fh)
        print("--------------------------------------------------------------------------------", file=self.fh)
        print("ColNo  Name                 Unit        Type           Shape       Range              Description", file=self.fh)

        try:
            dd = dmImageGetDataDescriptor(b)
            name = dmGetName( dd )
            unit = dmGetUnit( dd )
            dtype = self._get_dtype_string( dmGetDataType( dd ) )
            desc  = dmGetDesc( dd )
            dat  = dmImageGetData( dd )
            dims = dmGetArrayDimensions(dd)
            if ( dmGetArrayDim(dd) != len(dims) ):
                dimstr = "PROBLEM"
            elif ( dims.prod() != dmGetArraySize(dd) ):
                dimstr = "PROBLEM"
            else:
                dimstr = str(dims)

            if ( dmDescriptorIsVarLength(dd) == True ):
                dimstr = dimstr + " var"

            (rngmin,rngmax) = dmDescriptorGetRange(dd)
            rng = self.test_format_range( rngmin, rngmax )

            print("       %-20s %-10s %-15s %-10s %-15s %-25s" % (name, unit, dtype, dimstr, rng, desc), file=self.fh)

        except:
            raise

        if (name != dmGetCptName(dd,1)):
            print("       component name %s should be the same as descriptor name " % (name, dmGetCptName(dd,1)), file=self.fh)

        # Display Axis info
        print("", file=self.fh)
        print("--------------------------------------------------------------------------------", file=self.fh)
        print("Axis Transforms for Image Block %s" % dmBlockGetName( b ), file=self.fh)
        print("--------------------------------------------------------------------------------", file=self.fh)
        print("Group#  Axis#", file=self.fh)

        try:
            ngroups = dmArrayGetNoAxisGroups(dd)
            for ii in range(1,ngroups+1):
                dd = dmArrayGetAxisGroup(dd, ii )
                name = dmGetName(dd)
                print(" %3ld       NI   %s" % (ii,name), file=self.fh)

                ncoords = dmDescriptorGetNoCoords( dd )
                for jj in range  (1,ncoords+1):
                    cdd = dmDescriptorGetCoord(dd, jj)
                    name  = dmGetName( cdd )
                    print(" %3ld       NI   %s" % (ii,name), file=self.fh)
        except:
            raise

        # close up
        try:
            dmImageClose(b)
        except:
            raise



    # ----------------------------------------------------------------------
    # Block Copy
    # ----------------------------------------------------------------------
    def test_5( self ):
        """
        Dataset
          dmDatasetClose
          dmDatasetCreate
          dmDatasetOpen
          dmDatasetWriteable
          
        Block
          dmBlockClose
          dmBlockCopy             
          dmBlockCopyCol                
          dmBlockCopyData                
          dmBlockCopyWCS                 # NOT IMPLEMENTED
          dmBlockCreateCopy
          dmBlockCreateGenCopy
          dmBlockOpen(ds,btype)
        """
        
        print("Running Test 5", file=self.fh)

        # Assign input/output file names

        if sys.version_info[0] < 3:
            infile  = bytes(self.indir + self.infiles[0])
        else:
            infile  = bytes(self.indir + self.infiles[0], "utf-8")
        outfile = self.outdir + self.outfiles[1]

        # Open input file
        try:
            srcds = dmDatasetOpen( infile )
            srcb  = dmBlockOpen( b"TABONE", srcds, blktype=dmTABLE, update=False )
        except:
            raise

        # create the output dataset
        try:
            destds = dmDatasetCreate( outfile )
        except:
            raise

        # check write status
        if dmDatasetWriteable( srcds ):
            raise RuntimeError( "test_5():  Source dataset is writeable" )
        elif not dmDatasetWriteable( destds ):
            raise RuntimeError( "test_5():  Destination dataset is NOT writeable" )


        # copy the block to output file..
        try:
            if sys.version_info[0] < 3:
                histstr = bytes("test.py::dmBlockCreateGenCopy(ds, TPROPS, srcblock, histstr, True, False)")
                tab = dmBlockCreateGenCopy( destds, bytes("TPROPS"), srcb, histstr, True, False )
            else:
                histstr = bytes("test.py::dmBlockCreateGenCopy(ds, TPROPS, srcblock, histstr, True, False)", "utf-8")
                tab = dmBlockCreateGenCopy( destds, bytes("TPROPS","utf-8"), srcb, histstr, True, False )
        except:
            raise

        # copy again using other function.. no data this time
        try:
            etab = dmBlockCreateCopy( destds, b"EPROPS", srcb, copydata=False )
        except:
            raise


        #dmBlockCopyCol- copy fcol and sky cols from src to 3rd table 
        outb = dmDatasetCreateTable( destds, b"TESTTAB") 
        indesc = dmTableOpenColumn( srcb, b"FCOL");
        outdesc=dmBlockCopyCol(outb, indesc)
        indesc = dmTableOpenColumn( srcb, "SKY");
        outdesc=dmBlockCopyCol(outb, indesc)
        

        #dmBlockCopyData- table 
        infile2  = self.indir + self.infiles[3]
        tblsrc = dmTableOpen(infile2)
        outc = dmBlockCreateCopy( destds, "GTI9", tblsrc, copydata=True)
        infile3  = self.indir + self.infiles[4]
        dmBlockFlush(outc)
        tblsrc2 = dmTableOpen(infile3)
        dmBlockCopyData(tblsrc2, outc) 

        #dmBlockCopyData- image block 
        imgsrc1  = dmBlockOpen( "IMGTWO", srcds, blktype=dmIMAGE, update=False)
        imgtab = dmBlockCreateCopy( destds, "IMGDATA", imgsrc1, copydata=False)
        imgsrc2  = dmBlockOpen( "IMGONE", srcds, blktype=dmIMAGE, update=False)
        dmBlockCopyData(imgsrc2, imgtab)

        #dmBlockCopy- copy header from TPROPS to TESTTAB 
        dmBlockCopy(srcb, outb, b"HeadeR") 

        #dmBlockCopy- should fail w/ invalid option 'data'
        try:
            dmBlockCopy(srcb, outb, "data")
        except ValueError as e:
            print("", file=self.fh)
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        

        #dmBlockCopyWCS = NOT IMPLEMENTED

        # close up
        try:
            dmBlockClose( srcb )
            dmBlockClose(tab)
            dmBlockClose(etab)
            dmBlockClose(outb)
            dmBlockClose(outc)
            dmBlockClose(imgtab)
            dmBlockClose(imgsrc1)
            dmBlockClose(imgsrc2)
            dmBlockClose(tblsrc)
            dmBlockClose(tblsrc2)
            dmDatasetClose(srcds)
            dmDatasetClose(destds)
        except:
            raise


    # ----------------------------------------------------------------------
    # Table Create
    # ----------------------------------------------------------------------
    def test_6( self ):
        """
        Dataset
          dmDatasetClose
          dmDatasetCreate
          dmDatasetCreateTable
          
        Block
          dmBlockClose
          dmBlockFlush
          dmBlockCreate                
          dmBlockWriteComment          
          dmTableCreate

        Descriptor
          dmKeyWrite
          dmColumnCreate
        """
        print("Running Test 6", file=self.fh)
        
        # Assign input/output file names
        out1 = self.outdir + self.outfiles[0]
        out2 = self.outdir + self.outfiles[3]

        # create the dataset
        try:
            ds = dmDatasetCreate( out1 )
        except:
            raise

        # create a table extension
        try:
            tab = dmDatasetCreateTable( ds, "TABONE" )
        except:
            raise

        # Write some header keys
        try:
            self.test_create_keys( tab )
        except:
            raise

        try:
            self.test_create_columns( tab )
        except:
            raise

        # Alternate Table block creation functions.
        try:
            t2 = dmTableCreate( out2 )
            self.test_create_keys( t2 )  # put something in it.
            
            #dmBlockCreate    
            bl2 = dmBlockCreate(ds, b'EVENTS', dmTABLE)

        except:
            raise

        # add history/comment entry via dmBlockWriteComment  
        try:
            dmBlockWriteComment( t2, "Note", "Shouldn't work")
        except ValueError as e:
            print("", file=self.fh)
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass

        try:
            dmBlockWriteComment( t2, b"Comment", b"Test of dmBlockWriteComment wrapper")
        except:
            raise

        try:
            dmBlockWriteComment( t2, "HISTORY", "Modified by python cxcdm module")
        except:
            raise

        # flush buffer
        try:
            dmBlockFlush(None) 
        except TypeError as e:
            print("", file=self.fh)
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass

        try:
            dmBlockFlush()
        except TypeError as e:
            print("", file=self.fh)
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass

        try:
            dmBlockFlush(t2)
        except:
            raise

        # close up
        try:
            dmBlockClose(tab)
            dmBlockClose(bl2)
            dmDatasetClose(ds)
            dmTableClose(t2)
        except:
            raise


    # ----------------------------------------------------------------------
    # Image Create
    # ----------------------------------------------------------------------
    def test_7( self ):
        """
        Dataset
          dmDatasetClose
          dmDatasetCreateImage
          dmImageCreate
          
        Block
          dmBlockClose
          dmBlockGetDataset
          dmBlockWriteComment       
          dmImageGetDataDescriptor
          
        Descriptor
          dmKeyWrite
          dmArrayCreateAxisGroup          # NOT IMPLEMENTED
          dmGetCurrentArraySize
        """
        
        print("Running Test 7", file=self.fh)

        outfile = self.outdir + self.outfiles[2]

        axes = np.array([5,3], dtype=np.short);

        # create an image file
        try:
            im1 = dmImageCreate( outfile+"[IMGONE]", np.int32, axes )
        except:
            raise

        # write sample keyword set to block
        try:
            self.test_create_keys( im1 )
        except:
            raise

        # write a comment via dmBlockWriteComment 
        try:
            dmBlockWriteComment( im1, "COMMENT", "added via cxcdm python module test 7")
        except:
            raise

        # create an image extension
        try:
            ds = dmBlockGetDataset( im1 )
            im2 = dmDatasetCreateImage( ds, b"IMGTWO", np.int32, axes )
        except:
            raise

        try:
            dd = dmImageGetDataDescriptor(im1)
            size = dmGetCurrentArraySize(dd) 
            if ( size != axes.prod() ):
                raise Exception

            #dmArrayCreateAxisGroup   # NOT IMPLEMENTED
        except:
            raise

        # close up
        try:
            dmBlockClose(im1)
            dmBlockClose(im2)
            dmDatasetClose(ds)
        except:
            raise


    # ----------------------------------------------------------------------
    # Descriptor Data Table Read/Write (Column)
    # ----------------------------------------------------------------------
    def test_8( self ):
        """
        Block
          dmBlockAdvanceKeys           
          dmBlockDelete
          dmBlockGetKey
          dmBlockGetNoKeys             
          dmBlockMoveToKey             
          
          dmTableOpen(file,update)
          dmTableOpenColumn

          dmKeyOpen                    # NOT IMPLEMENTED
          dmKeyRead
          dmKeyWrite                   # NOT IMPLEMENTED
          
        Descriptor
          dmSetName                    # NOT IMPLEMENTED*
          dmSetDesc
          dmSetDisp
          dmSetUnit
          dmSetCptName                
          dmDescriptorGetBin           
          dmDescriptorSetBin           
          dmDescriptorSetNull          
          dmDescriptorSetRange
          dmDescriptorDelete           
          dmDescriptorCompare       
          dmGetData
          dmSetData
        """
        
        print("Running Test 8", file=self.fh)

        # Assign input/output file names
        infile  = self.indir + self.infiles[0]
        outfile = self.outdir + self.outfiles[4]

        # copy input file to output location for update
        os.system("cp " + infile + " " + outfile)


        # Open input file
        try:
            tab = dmTableOpen( outfile, update=True )
        except:
            raise

        # retrieve string of all keys/comments
        try:
            vals = dmBlockListKeys(tab)
        except:
            raise

        if len(vals) > 0:
            print("  dmBlockListKeys(tab) ", file=self.fh)
            print("%s " % vals, file=self.fh) 
            print("", file=self.fh)

        # Pull out keyword and modify..
        print("  dmSet<Field>( k, svalue )                        # modify value/unit/description of keyword", file=self.fh)
        print("       Name            Unit       Type            Description", file=self.fh)
        try:
            (key,v) = dmKeyRead( tab, "IARRKEY1")
            self.test_print_key( key )

            dmSetUnit( key, "mm" )
            dmSetDesc( key, "distance along axis Np")
            dmSetData( key, v*1000 )
            print("    to", file=self.fh)

            self.test_print_key( key )
        except:
            raise

        # Pull out a column and modify..
        print("  dmSet<Field>( c, value )                         # modify value/unit/description of column", file=self.fh)
        print("       Name            Unit       Type            Description", file=self.fh)
        try:
            col = dmTableOpenColumn( tab, "JCOL")
            self.test_print_key( col )

            dmSetUnit( col, "au" )
            dmSetDesc( col, "distance from sun")
            print("    to", file=self.fh)
            self.test_print_key( col )

            # change data values for this column
            vals = dmGetData( col, 1, 4  ) + 1000
            dmSetData( col, vals )
        except:
            raise

        print("", file=self.fh)

        # check number of keys- 
        nkeys = dmBlockGetNoKeys(tab)
        print("  dmBlockGetNoKeys(tab) = %d\n" % nkeys, file=self.fh) 

        # move around within block 
        try:
            keyno = int(nkeys/2)
            key = dmBlockMoveToKey(tab, keyno )
            self.test_print_key( key )
        except Exception as e:
            print(e)
            raise

        try:
            keyno = 14
            key = dmBlockGetKey(tab, keyno)
            self.test_print_key( key )
        except RuntimeError as e:
            print(e)
            raise

        # move around within block 
        try:
            key = dmBlockMoveToKey(tab, 12)
        except:
            raise 
        print("", file=self.fh)
        print("  dmBlockMoveToKey to Key 12 - %s" % dmGetName(key), file=self.fh)

        try:
            key = dmBlockMoveToKey(tab, 15)
        except:
            raise 
        print("  dmBlockMoveToKey to Key 15 - %s" % dmGetName(key), file=self.fh)

        try:
            key = dmBlockAdvanceKeys(tab, -3)
        except:
            raise 
        print("  dmBlockAdvanceKeys -3 to - %s" % dmGetName(key), file=self.fh)

        try:
            key = dmBlockAdvanceKeys(tab, 50)
        except ValueError as e:
            print("", file=self.fh)
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
 
        try:
            key = dmBlockAdvanceKeys(tab, -20)
        except ValueError as e:
            print("", file=self.fh)
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass

        try:
            key = dmBlockAdvanceKeys(tab, 1)
        except:
            raise 
        print("", file=self.fh)
        print("  dmBlockAdvanceKeys 1 to - %s" % dmGetName(key), file=self.fh)
        print("", file=self.fh)

        # Delete keyword
        try:
            key = dmBlockGetKey(tab, 6)
            print("  dmDescriptorDelete() - key %s" % dmGetName(key), file=self.fh)
            dmDescriptorDelete( key )
        except:
            raise 
        
        # Delete column
        try:
            col = dmTableOpenColumn( tab, "BCOL")
            print("  dmDescriptorDelete() - col %s" % dmGetName(col), file=self.fh)
            dmDescriptorDelete( col )
        except Exception as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            print("", file=self.fh)
            pass
        else:
            raise RuntimeError ("     Unexpected Pass ... FAIL")


        # compare descriptors
        d2=dmBlockGetKey(tab, 2)
        d3=dmBlockGetKey(tab, 3)
        print(" Comparing %s with %s" % (dmGetName(d2), dmGetName(d3)), file=self.fh)
        print("    dmDESCNAME: %s " % dmDescriptorCompare(d2,d3,dmDESCNAME), file=self.fh) 
        print("    dmDESCVALUE: %s " % dmDescriptorCompare(d2,d3,dmDESCVALUE), file=self.fh) 
        print("    dmDESCUNIT: %s " % dmDescriptorCompare(d2,d3,dmDESCUNIT), file=self.fh) 
        print("    dmDESCKIND: %s " % dmDescriptorCompare(d2,d3,dmDESCKIND), file=self.fh) 
        print("    dmDESCTYPE: %s " % dmDescriptorCompare(d2,d3,dmDESCTYPE), file=self.fh) 
        print("    dmDESCELMTYPE: %s " % dmDescriptorCompare(d2,d3,dmDESCELMTYPE), file=self.fh) 
        print("    dmDESCDIM: %s " % dmDescriptorCompare(d2,d3,dmDESCDIM), file=self.fh) 
        print("    dmDESCLENS: %s " % dmDescriptorCompare(d2,d3,dmDESCLENS), file=self.fh) 
        print("    dmDESCELMDIM: %s " % dmDescriptorCompare(d2,d3,dmDESCELMDIM), file=self.fh) 
        print("    dmDESCCPTNAMES: %s " % dmDescriptorCompare(d2,d3,dmDESCCPTNAMES), file=self.fh) 
        print("    dmDESCCMNT: %s " % dmDescriptorCompare(d2,d3,dmDESCCMNT), file=self.fh) 
        print("    dmDESCALL: %s " % dmDescriptorCompare(d2,d3,dmDESCALL), file=self.fh) 
        print("    dmDESCUNIT|dmDESCLENS: %s " % dmDescriptorCompare(d2,d3,dmDESCUNIT|dmDESCLENS), file=self.fh) 
        print("    dmDESCUNIT|dmDESCLENS|dmDESCVALUE: %s " % dmDescriptorCompare(d2,d3,dmDESCUNIT|dmDESCLENS|dmDESCVALUE), file=self.fh) 
        print("    dmDESCALL&~dmDESCNAME&~dmDESCVALUE: %s " % dmDescriptorCompare(d2,d3,dmDESCALL&~dmDESCNAME&~dmDESCVALUE), file=self.fh) 
        print("    dmDESCALL&~dmDESCNAME&~dmDESCVALUE&~dmDESCCPTNAMES&~dmDESCCMNT: %s " % dmDescriptorCompare(d2,d3,dmDESCALL&~dmDESCNAME&~dmDESCVALUE&~dmDESCCPTNAMES&~dmDESCCMNT), file=self.fh) 
        print("", file=self.fh)

        fcol = dmTableOpenColumn( tab, "FCOL")
        facol = dmTableOpenColumn( tab, "FACOL")
        print(" Comparing %s with %s" % (dmGetName(fcol), dmGetName(facol)), file=self.fh)
        print("    dmDESCUNIT: %s " % dmDescriptorCompare(fcol,facol,dmDESCUNIT), file=self.fh)
        print("    dmDESCLENS: %s " % dmDescriptorCompare(fcol,facol,dmDESCLENS), file=self.fh)
        print("    dmDESCTYPE: %s " % dmDescriptorCompare(fcol,facol,dmDESCTYPE), file=self.fh)
        print("    dmDESCELMDIM: %s " % dmDescriptorCompare(fcol,facol,dmDESCELMDIM), file=self.fh)
        print("    dmDESCELMTYPE: %s " % dmDescriptorCompare(fcol,facol,dmDESCELMTYPE), file=self.fh)
        try:
            rr = dmDescriptorCompare(fcol,facol, 0)
        except Exception as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            print("", file=self.fh)
            pass
        else:
            raise RuntimeError ("     Unexpected Pass ... FAIL")

        # close up
        try:
            dmTableClose(tab)
        except:
            raise

       # Try updating TNULL, TDBIN values 
        try:
            tab2 = dmTableOpen( outfile, update=True )
            c2 = dmTableOpenColumn( tab2, "ICOL")
            c4 = dmTableOpenColumn( tab2, "FCOL")
            c6 = dmTableOpenColumn( tab2, "BCOL")

            ov2 = dmDescriptorGetNull(c2)
            if (ov2 is None ):
                ov2 = 0
            ov4 = dmDescriptorGetNull(c4)
            if (ov4 is None ):
                ov4 = 0.0
            ov6 = dmDescriptorGetNull(c6)
            if (ov6 is None ):
                ov6 = np.byte(0)
            bov2 = dmDescriptorGetBin(c2)
            bov4 = dmDescriptorGetBin(c4)
            bov6 = dmDescriptorGetBin(c6)

            dmGetDisp(c2)
            dmGetDisp(c4)
            dmSetDisp(c2,"I4")
            dmSetDisp(c4,b"F5.2")

            dmDescriptorSetNull(c2, -1)
            dmDescriptorSetNull(c4, 303.0)
            dmDescriptorSetNull(c6, np.byte(53))
            dmDescriptorSetBin(c2, 7)
            dmDescriptorSetBin(c4, 22.3)
            dmDescriptorSetBin(c6, np.byte(3))
 
            dmDescriptorSetRange(c2, 100, 110)
            dmDescriptorSetRange(c4, 300.0, 310.0)

            sky = dmTableOpenColumn( tab2, "sky")
            oc1name = dmGetCptName(sky, 1)
            oc2name = dmGetCptName(sky, 2)
            dmSetCptName(sky, 1, b"blue")
            dmSetCptName(sky, 2, "apple")
            dmTableClose(tab2)

            tab = dmTableOpen(outfile)
            c2 = dmTableOpenColumn( tab, "ICOL")
            c4 = dmTableOpenColumn( tab, "FCOL")
            c6 = dmTableOpenColumn( tab, "BCOL")
       
            nv2 = dmDescriptorGetNull(c2)
            nv4 = dmDescriptorGetNull(c4)
            nv6 = dmDescriptorGetNull(c6)
            bnv2 = dmDescriptorGetBin(c2)
            bnv4 = dmDescriptorGetBin(c4)
            bnv6 = dmDescriptorGetBin(c6)
   
            (rnvl2,rnvu2) = dmDescriptorGetRange(c2)
            (rnvl4,rnvu4) = dmDescriptorGetRange(c4)

            sky = dmTableOpenColumn( tab, "sky")
            nc1name = dmGetCptName(sky, 1)
            nc2name = dmGetCptName(sky, 2)
            dmTableClose(tab)

            print("  check dmDescriptorSetNull... ", file=self.fh)
            print("    TNULL for ICOL changed from %d to %d" % (ov2, nv2), file=self.fh)
            print("    TNULL for FCOL changed from %4.1f to %4.1f" % (ov4, nv4), file=self.fh)
            print("    TNULL for BCOL changed from %d to %d" % (ov6, nv6), file=self.fh)
            print("", file=self.fh)
            print("  check dmDescriptorSetBin... ", file=self.fh)
            print("    TDBIN for ICOL changed from %d to %d" % (bov2, bnv2), file=self.fh)
            print("    TDBIN for FCOL changed from %4.1f to %4.1f" % (bov4, bnv4), file=self.fh)
            print("    TDBIN for BCOL changed from %d to %d" % (bov6, bnv6), file=self.fh)
            print("", file=self.fh)
            print("  check dmDescriptorSetRange... ", file=self.fh)
            print("    TLMIN/TLMAX for ICOL now %d:%d" % (rnvl2, rnvu2), file=self.fh)
            print("    TLMIN/TLMAX for FCOL now %4.1f:%4.1f" % (rnvl4, rnvu4), file=self.fh)
            print("", file=self.fh)
            print("  check dmSetCptName... ", file=self.fh)
            print("    component 1 of sky changed from %s to %s" % (oc1name, nc1name), file=self.fh)
            print("    component 2 of sky changed from %s to %s" % (oc2name, nc2name), file=self.fh)
            print("", file=self.fh)
        except:
            raise


       # Delete Image block from dataset
        try:
            print("  check dmBlockDelete()... ", file=self.fh)
            b = dmBlockOpen( outfile+"[IMGONE]",update=True )
            dmBlockDelete(b)
        except:
            raise
        else:
            print("    block 'IMGONE' should be deleted", file=self.fh)
            print("", file=self.fh)




    # ----------------------------------------------------------------------
    # Descriptor Data Table Read/Write (Row)
    # ----------------------------------------------------------------------
    def test_9( self ):
        """
        Block
          dmTableAllocRow
          dmTableGetRow
          dmTableGetRows
          dmTableGetRowNo
          dmTableNextRow
          dmTableOpen(file,update)
          dmTablePutRow                    # NOT IMPLEMENTED
          dmTableSetRow                    
        """
        
        print("Running Test 9", file=self.fh)

        # Assign input/output file names
        infile  = self.indir + self.infiles[0]
        outfile = self.outdir + self.outfiles[5]

        # copy input file to output location for update
        os.system("cp " + infile + " " + outfile)


        # Open input file
        try:
            tab = dmTableOpen( outfile, update=True )
        except:
            raise

        nrows = dmTableGetNoRows(tab)
        for ii in range(nrows):
            print("", file=self.fh)
            print("row = dmTableGetRow(tab)       # load row %ld" % ii, file=self.fh)
            row = dmTableGetRow(tab)
            print(row, file=self.fh)

        print("", file=self.fh)
        print("row = dmTableAllocRow(tab)     # make empty row", file=self.fh)
        row = dmTableAllocRow(tab)
        print("empty row:", file=self.fh)
        print(row, file=self.fh)

        # test row setting
        pos = dmTableSetRow(tab, 1)                             # first row
        print("", file=self.fh)
        print(" dmTableSetRow(tab, 1) set row to %d" % pos, file=self.fh)

        pos = dmTableSetRow(tab, dmENDOFTABLE)                  # last row
        if pos == dmNOMOREROWS:
           print(" dmTableSetRow(tab, dmENDOFTABLE) set row to dmNOMOREROWS", file=self.fh) 
        else:
           print(" dmTableSetRow(tab, dmENDOFTABLE) set row to %d" % pos, file=self.fh)
        pos = dmTableSetRow(tab, 5)                             # fifth row
        if pos == dmNOMOREROWS:
           print(" dmTableSetRow(tab, 5) set row to dmNOMOREROWS {dmTableGetNoRows() = %d}" % dmTableGetNoRows(tab), file=self.fh) 
        else:
           print(" dmTableSetRow(tab, 5) set row to %d" % pos, file=self.fh)
        
        print("", file=self.fh)
        print("dmTableSetRow(tab, 3)          # go to row", file=self.fh)
        dmTableSetRow(tab, 3)

        print("dmTableGetRowNo(tab)           # verify row", file=self.fh)
        print(dmTableGetRowNo(tab), file=self.fh)

        # test buffer size setting
        try:
           dmBlockSetBufferMaxSize(tab)
        except TypeError as e:
            print("", file=self.fh)
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
     
        try:
           dmBlockSetBufferMaxSize(3, "A")
        except TypeError as e:
            print("", file=self.fh)
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass

        try:
           dmBlockSetBufferMaxSize(tab, 32)
        except:
            raise


        print("dmTableGetRows(tab, 2 )        # read row(s) of data", file=self.fh)
        rows = dmTableGetRows(tab, 2 )

        print(" Change values of certain columns (LCOL, FCOL,IACOL)", file=self.fh)
        rows['lcol'][0] = True
        rows['fcol'][0] += 0.0250
        rows['iacol'][0][2] *= 0

        print("dmTableSetRow(tab, 2)          # go back to row before", file=self.fh)
        #dmTableSetRow(tab, 3)                                      # NOT IMPLEMENTED
        print("dmTableNextRow(tab)            # advance one", file=self.fh)
        #dmTableNextRow(tab)                                        # NOT IMPLEMENTED

        print("dmTablePutRow(tab, rows)       # write values", file=self.fh)
        #dmTablePutRow(tab, rows)             # replace values      # NOT IMPLEMENTED

        print("dmTableClose(tab))             # close up", file=self.fh)
        # close up
        try:
            dmTableClose(tab)
        except:
            raise

    # ----------------------------------------------------------------------
    # Descriptor Image Data Read/Write
    # ----------------------------------------------------------------------
    def test_10( self ):
        """
        Block
          dmImageClose                   
          dmImageOpen(update)

          dmImageGetData
          dmImageSetData
        """
        
        print("Running Test 10", file=self.fh)

        # Assign input/output file names
        infile  = self.indir + self.infiles[0]
        outfile = self.outdir + self.outfiles[6]

        # copy input file to output location for update
        os.system("cp " + infile + " " + outfile)

        # open the Image 
        try:
            print("  dmImageOpen(<file>[IMGTWO], update=True)  # open image extension", file=self.fh)
            img = dmImageOpen( outfile + "[IMGTWO]" , update=True)
            print("  dd = dmImageGetDataDescriptor( img )      # get image descriptor", file=self.fh)
            dd  = dmImageGetDataDescriptor(img)
        except:
            raise

        print("  dmImageGetData( dd )                      # read image data", file=self.fh)
        try:
            print("                                            # modify image values", file=self.fh)
            dat = dmImageGetData( dd )
            dat += 7
            print("  dmImageSetData( dd )                      # set image data", file=self.fh)
            dmImageSetData( dd, dat )
        except:
            raise

        print("  dmImageClose(img))                        # close up", file=self.fh)
        # close up
        try:
            dmImageClose(img)
        except:
            raise

    # ----------------------------------------------------------------------
    # Subspace
    # ----------------------------------------------------------------------
    def test_11( self ):
        """
        Dataset
          dmDatasetClose
          
        Block
          dmBlockClose
          dmBlockOpen(update)
          dmBlockGetSubspace              
          dmBlockGetSubspaceCol 
          dmBlockGetNoSubpaceCols         
          dmBlockGetNoSubspaceCpts
          dmBlockGetCurrSubspaceCpt      
          dmBlockSubspaceColOpen

        Descriptor
          dmSubspaceColGetTableName       
          dmSubspaceColSetTableName       
          dmSubspaceColCreate             # NOT IMPLEMENTED
          dmSubspaceColGet
          dmSubspaceColSet                
          dmSubspaceColUpdate            
          dmSubspaceColRead               # NOT IMPLEMENTED
          dmSubspaceColSetRegion          
          dmSubspaceColGetRegion          
        """
        
        print("Running Test 11", file=self.fh)

        # Assign input/output file names
        infile  = self.indir + self.infiles[0]
        outfile = self.outdir + self.outfiles[7]
        outfile2 = self.outdir + self.outfiles[12]

        # copy input file to output location for update
        os.system("cp " + infile + " " + outfile)

        try:
            b = dmBlockOpen( outfile, update=True )
        except:
            raise

        try:
            nss = dmBlockGetNoSubspaceCpts( b )
            ncols = dmBlockGetNoSubspaceCols( b )
        except:
            raise
        
        print("--------------------------------------------------------------------------------", file=self.fh)
        print("Data subspace for block <name>: Components: %ld  Descriptors: NI " % nss, file=self.fh)
        print("          Number of subspace cols: %2d" % ncols, file=self.fh) 
        print("--------------------------------------------------------------------------------", file=self.fh)

        for ii in range(nss):
            print("--- Component %ld --- " % ii, file=self.fh)
            for colname in ("icol","facol","sky"):
                try:
                    sc1 = dmSubspaceColOpen( b , colname )
                    name  = dmGetName( sc1 )
                    dtype = self._get_dtype_string( dmGetDataType( sc1 ) )
                    if (colname == "icol" ):
                        dmSubspaceColSet(sc1, [1,50],[10,100])
                    (mins,maxes) = dmSubspaceColGet( sc1 )
                    if len(mins) == 0:
                        rstr = "DEFAULT"
                    else:
                        rstr = ""
                        for ndx in range(len(mins)):
                            rstr += "(%ld:%ld)" % (mins[ndx], maxes[ndx])

                    #  no name                 dtype               range
                    print(" NI %-20s %-20s %-s" % (name, dtype, rstr), file=self.fh)
                except:
                    raise

        print(" ", file=self.fh)
        print(" checking dmBlockGetSubspace...", file=self.fh) 
        try:
           (ncpts, ncols, descs) = dmBlockGetSubspace(b)
           print("  got %d subspace cols " % ncols, file=self.fh) 
           for ii in range(ncols):
              d=dmBlockGetSubspaceCol(b,ii+1)
              name = dmGetName(d)
              d2 = dmBlockGetSubspaceCol(b, name)
              if dmGetName(d) != dmGetName(descs[ii]):
                 print(" different desc names %s & %s" % (dmGetName(d), dmGetName(descs[ii])), file=self.fh)
              elif dmGetName(d2) != name:
                 print(" different desc names %s & %s" % (dmGetName(d2), name), file=self.fh)
              else:
                 print(" dmBlockGetSubspaceCol(b, %d) == dmBlockGetSubspaceCol(b, '%s') == desc[%d]" % (ii+1, name, ii), file=self.fh)
        except:
            raise 

        # close up
        try:
            ds = dmBlockGetDataset(b)
            dmBlockClose(b)
            dmDatasetClose(ds)
        except:
            raise

        # test Subspace gets on time/sky cols 
        try:
            b = dmBlockOpen( self.indir + self.infiles[2] )
            d3 = dmTableOpenColumn(b,3)
            (d4,x) = dmKeyRead(b,"OBSERVER")
             
            # test Subspace functions
            print(" ", file=self.fh)
            for colname in ("time","chip","sky"):
                dd  = dmBlockGetSubspaceCol(b, colname)
                reg = dmSubspaceColGetRegion( dd )

                print("  %-4s column- table name   : %s " % (colname,dmSubspaceColGetTableName(dd)), file=self.fh)
                if ( colname == "time" ):
                    print("               dmSubspaceColSetTableName( dd, 'GTI4') ", file=self.fh)
                    dmSubspaceColSetTableName( dd, b"GTI4" )
                    print("             - table name   : %s " % dmSubspaceColGetTableName(dd), file=self.fh)
                
                print("             - region string: %s " % dmSubspaceColGetRegionString(dd), file=self.fh)

                if ( reg is None ):
                    print("             - region object: None ", file=self.fh)
                    if ( colname == "chip" ):
                        print("               dmSubspaceColSetRegion( dd, regParse('circle(512,512,500)') ) ", file=self.fh)
                        dmSubspaceColSetRegion( dd, regParse("circle(512,512,500)"), b"GTI4" )
                        reg = dmSubspaceColGetRegion( dd )
                        print("             - region object: %s " % regRegionString( reg ), file=self.fh)
                    
                else:
                    print("             - region object: %s " % regRegionString( reg ), file=self.fh)
            print(" ", file=self.fh)

        except:
            raise

        print(" ", file=self.fh)
        print("  try w/ dmColumn descriptor: ", file=self.fh)
        try:
            dmSubspaceColGetTableName(d3)
        except ValueError as e:
            print("", file=self.fh)
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass

        try:
            dmSubspaceColGetRegionString(d3)
        except ValueError as e:
            print("", file=self.fh)
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass

        print(" ", file=self.fh)
        print("  try w/ dmKey descriptor   : ", file=self.fh)
        try:
            dmSubspaceColGetTableName(d4)
        except ValueError as e:
            print("", file=self.fh)
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass

        try:
            dmSubspaceColGetRegionString(d4)
        except ValueError as e:
            print("", file=self.fh)
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass

        print(" ", file=self.fh)
        print("  check dmBlockGetCurrSubspaceCpt  ", file=self.fh)
     
        print("    current subspace cpt: %1d " % dmBlockGetCurrSubspaceCpt(b), file=self.fh)
        dmBlockSetSubspaceCpt(b,4)
        print("    move to subspace cpt- 4 ", file=self.fh)
        print("    current subspace cpt: %1d " % dmBlockGetCurrSubspaceCpt(b), file=self.fh)
        dmBlockSetSubspaceCpt(b,2)
        print("    move to subspace cpt- 2 ", file=self.fh)
        print("    current subspace cpt: %1d " % dmBlockGetCurrSubspaceCpt(b), file=self.fh)
        dmBlockSetSubspaceCpt(b,5)
        print("    move to subspace cpt- 5 ", file=self.fh)
        print("    current subspace cpt: %1d " % dmBlockGetCurrSubspaceCpt(b), file=self.fh)
        dmBlockSetSubspaceCpt(b,3)
        print("    move to subspace cpt- 3 ", file=self.fh)
        print("    current subspace cpt: %1d " % dmBlockGetCurrSubspaceCpt(b), file=self.fh)

        try:
            dmBlockClose(b)
        except:
            raise

        # copy input file to output location for update
        print("", file=self.fh)
        print("  check dmSubspaceColSet vs dmSubspaceColUpdate", file=self.fh)
        os.system("cp " + outfile + " " + outfile2)

        tt=dmTableOpen(outfile2, update=True)
        sc1 =dmSubspaceColOpen(tt,"ICOL")
        (min,max)=dmSubspaceColGet(sc1)
        dmSubspaceColSet(sc1, 4,28)
        (min2,max2)=dmSubspaceColGet(sc1)
        print("    set- ICOL range (%d:%d) w/ 4,28  -> (%d,%d)" % (min[0], max[0], min2[0], max2[0]), file=self.fh) 

        dmSubspaceColSet(sc1, [2,60],[11,110])
        (min,max)=dmSubspaceColGet(sc1)
        print("    set- ICOL range (%d,%d) w/ 2:11,60:110  -> (%d:%d)(%d,%d)" % (min2[0], max2[0], min[0], max[0], min[1], max[1]), file=self.fh) 
 
        dmSubspaceColUpdate(sc1, [7,45],[15,89])
        (min2,max2)=dmSubspaceColGet(sc1)
        print("    intersect- ICOL range (%d:%d)(%d,%d) w/ 7:15,45:89  -> (%d:%d)(%d,%d)" % (min[0], max[0], min[1], max[1], min2[0], max2[0], min2[1], max2[1]), file=self.fh) 
        print("", file=self.fh)

        sc2 =dmSubspaceColOpen(tt,"sky")

        (min,max)=dmSubspaceColGet(sc2)
        dmSubspaceColUpdate(sc2, -10000, 10000)
        (min2,max2)=dmSubspaceColGet(sc2)
        print("    intersect- SKY range (%d:%d) w/ -10000,10000  -> (%d:%d)" % (min[0], max[0], min2[0],max2[0]), file=self.fh) 
        dmSubspaceColSet(sc2, -10000, 10000)
        (min,max)=dmSubspaceColGet(sc2)
        print("    set- SKY range (%d:%d) w/ -10000,10000  -> (%d:%d)" % (min2[0], max2[0], min[0],max[0]), file=self.fh) 
        dmSubspaceColUpdate(sc2, 3000, 5000)
        (min2,max2)=dmSubspaceColGet(sc2)
        print("    intersect- SKY range (%d:%d) w/ 3000,5000  -> (%d:%d)" % (min[0], max[0], min2[0],max2[0]), file=self.fh) 

        print("", file=self.fh)
        dmTableClose(tt)

        # test dmSubspaceColRead
        print("  check dmSubspaceColRead  ", file=self.fh)
        tt=dmTableOpen(outfile2)
        (sc1, min, max) = dmSubspaceColRead(tt,"ICOL")
        (min2,max2)=dmSubspaceColGet(sc1)
        print("    dmSubspaceColRead(ICOL) -> (%d:%d)(%d,%d)  vs  Get(ICOL) -> (%d:%d)(%d,%d)" % (min[0], max[0], min[1], max[1], min2[0], max2[0], min2[1], max2[1]), file=self.fh)         
        (sc1, min, max) = dmSubspaceColRead(tt,b"SKY")
        (min2,max2)=dmSubspaceColGet(sc1)
        print("    dmSubspaceColRead(SKY) -> (%d:%d)  vs Get(SKY) -> (%d,%d)" % (min[0], max[0], min2[0], max2[0]), file=self.fh)

        print("    dmSubspaceColRead(SCOL)", file=self.fh)
        try:
            (sc1, min, max) = dmSubspaceColRead(tt,"SCOL")
        except ValueError as e:
            print("", file=self.fh)
            print("    ", str(e), file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass

        print("    dmSubspaceColGet(SCOL)", file=self.fh)
        try:
            (min2,max2)=dmSubspaceColGet(sc1)
        except ValueError as e:
            print("", file=self.fh)
            print("    ", str(e), file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass


        print("    dmSubspaceColRead(XCOL)", file=self.fh)
        try:
            (sc1, min, max) = dmSubspaceColRead(tt,"XCOL")
        except ValueError as e:
            print("", file=self.fh)
            print("    ", str(e), file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass

        print("    dmSubspaceColGet(XCOL)", file=self.fh)
        try:
            (min2,max2)=dmSubspaceColGet(sc1)
        except ValueError as e:
            print("", file=self.fh)
            print("    ", str(e), file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass

        print("", file=self.fh)
        dmTableClose(tt)


        print("  check dmSubspaceColCreate  ", file=self.fh)
        tt=dmTableOpen(outfile2, update=True)

        for colname in ("newcol1", "newcol2", "newcol3", "gti", "sample"):
            try:
        
                if ( colname == "newcol1" ):
                    #
                    # Create Subspace TABLE 
                    #   NOTE: value dtype must be real?!
                    
                    # creates SSTAB block with cols NEWCOL1_MIN, NEWCOL1_MAX  (not expected)
                    # NOTE: Need to set table name manuallyb if not GTI.
                    dd = dmSubspaceColCreate(tt, b"SSTAB", b"NEWCOL1", None, b"U", [10.0,20.0], [30.0,40.0] )
                    dmSubspaceColSetTableName(dd, "SSTAB");

                    
                if ( colname == "newcol2" ):
                    #
                    # Create subspace vector colum to attach region. 
                    # (ranges should not be relevant here, component ranges set directly on component descriptor.)
                    #
                    dd = dmSubspaceColCreate(tt, None, "NEWCOL2", ["VECCPTX", "VECCPTY"], "U", [3800,3800], [4200,4200])
                    reg = regParse("Circle(4000,4000,200)")
                    dmSubspaceColSetRegion(dd, reg)


                if ( colname == "newcol3" ):
                    #
                    # Create subspace column with ranges.
                    #
                    dd = dmSubspaceColCreate(tt, None, "NEWCOL3", None, "U", [0, 2, 3, 4, 6], [0, 2, 3, 4, 6] )


                if ( colname == "gti" ):
                    # creates GTI block with cols start, stop
                    dd = dmSubspaceColCreate(tt, "GTI", "time", ["start","stop"], "sec", [1.0, 10.0, 100.0], [2.0, 20.0, 200.0])


                if ( colname == "sample" ):
                    #
                    # Create subspace column with ranges.
                    #
                    dd = dmSubspaceColCreate(tt, None, "sample", None, "sec", [1.0, 10.0,100.0], [2.0, 20.0,200.0])


                print("    - table name   : %s " % dmSubspaceColGetTableName(dd), file=self.fh)
                print("    - column name   : %s " % dmGetName(dd), file=self.fh)
                
                (sscol,min,max)=dmSubspaceColRead(tt, colname)
                print("      min:  ", min, file=self.fh)
                print("      max:  ", max, file=self.fh)                
                
                vdim = dmGetElementDim(dd)
                
                if vdim > 1:
                    for kk in range(vdim):                    
                        colcpt = dmGetCpt(dd, kk+1)
                        print("    - component name [%i]  : %s " % (kk, dmGetName(colcpt)), file=self.fh)
                        
                tmpreg = dmSubspaceColGetRegion(dd)
                if tmpreg:
                    print("    - region  : ", regRegionString( tmpreg ), file=self.fh)

                print("", file=self.fh)

            except Exception as ex:
                print(ex, " ", colname, file=self.fh) 
                pass
   

        print(file=self.fh)
        dmTableClose(tt)


    # ----------------------------------------------------------------------
    # Coordinates
    # ----------------------------------------------------------------------
    def test_12( self ):
        """
        Dataset
          dmDatasetClose
          
        Block
          dmBlockClose
          dmBlockOpen(update)
          
        Descriptor
          dmCoordCalc                    
          dmCoordInvert                  
          dmCoordGetAxisGroupNo          
          dmCoordGetParams               
          dmCoordGetTransform            
          dmCoordGetTransformType        
          dmCoordSetParam                
          dmCoordSetTransform
          dmDescriptorGetArea
        """
        
        print("Running Test 12", file=self.fh)

        # Assign input/output file names
        infile  = self.indir + self.infiles[2]
        outfile = self.outdir + self.outfiles[8]

        # copy input file to output location for update
        os.system("cp " + infile + " " + outfile)

        try:
            b = dmBlockOpen( outfile, update=True )

            dd = dmTableOpenColumn(b, "EQPOS")
        except:
            raise

        try:
            (ttype, nparam) = dmCoordGetTransformType( dd )
        except:
            raise

        try:
            (crpix,crval,cdelt) = dmCoordGetTransform (dd)
            params              = dmCoordGetParams(dd)
        except:
            raise
        
        print("EQPOS: \"%s\" Transform definition" % ttype, file=self.fh)
        print("   THETA: %8.2f" % params[0], file=self.fh)
        print("   LONP:  %8.2f" % params[1], file=self.fh)
        print("   LATP:  %8.2f" % params[2], file=self.fh)
        print("   EQNX:  %8.2f" % params[3], file=self.fh)
        print("", file=self.fh)
        print("             cpt_1     cpt_2", file=self.fh)
        print("   CRPIX:  %8.2f  %8.2f" % (crpix[0], crpix[1]), file=self.fh)
        print("   CRVAL:  %8.2f  %8.2f" % (crval[0], crval[1]), file=self.fh)
        print("   CDELT:  %8.6f  %8.6f" % (cdelt[0], cdelt[1]), file=self.fh)

        # test set coord transform
        try:
           dmCoordSetTransform(dd, ["A","B"], [166, 40], cdelt)  
        except TypeError as e:
            print("", file=self.fh)
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass

        try:
            dmCoordSetTransform(dd, crpix, [166, 40], [None,None])
        except TypeError as e:
            print("", file=self.fh)
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass

        try:
            dmCoordSetTransform(dd, crpix, [True,False], [0.1,.03])
        except TypeError as e:
            print("", file=self.fh)
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass

        try:
            dmCoordSetTransform(dd, crpix, crval, [0.1,.03,.1])
        except ValueError as e:
            print("", file=self.fh)
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass

        try:
            dmCoordSetTransform(dd, [3891.5,4102.5], [165, 38.3], cdelt)
        except:
            raise

        try:
            dmCoordSetParam(dd, 'EQUINOX', 1950.0 )
            dmCoordSetParam(dd, b'LONGPOLE', 90.0 )
            dmCoordSetParam(dd, 'LATPOLE',  10.0 )
            dmCoordSetParam(dd, 'ROT', 62.0 )
        except:
            raise



        # Pull values back out from coordinate descriptor.
        try:
            (crpix,crval,cdelt) = dmCoordGetTransform (dd)
            params              = dmCoordGetParams(dd)
        except:
            raise

        print("", file=self.fh)
        print(" modified crpix and crval to [3891.5,4102.5], [165, 38.3]", file=self.fh)
        print(" modified params to          [62.0, 90.0, 10.0, 1950.0]", file=self.fh)
        print("", file=self.fh)
        print("EQPOS: \"%s\" Transform definition" % ttype, file=self.fh)
        print("   THETA: %8.2f" % params[0], file=self.fh)
        print("   LONP:  %8.2f" % params[1], file=self.fh)
        print("   LATP:  %8.2f" % params[2], file=self.fh)
        print("   EQNX:  %8.2f" % params[3], file=self.fh)
        print("", file=self.fh)
        print("             cpt_1     cpt_2", file=self.fh)
        print("   CRPIX:  %8.2f  %8.2f" % (crpix[0], crpix[1]), file=self.fh)
        print("   CRVAL:  %8.2f  %8.2f" % (crval[0], crval[1]), file=self.fh)
        print("   CDELT:  %8.6f  %8.6f" % (cdelt[0], cdelt[1]), file=self.fh)
        print("", file=self.fh)

        # Display Column areas
        print("", file=self.fh)
        print("--------------------------------------------------------------------------------", file=self.fh)
        print("Column Areas:                                                                   ", file=self.fh)
        print("--------------------------------------------------------------------------------", file=self.fh)
        print("ColNo  Name                                 Area                       Field_Area", file=self.fh)

        cols = dmTableOpenColumnList( b )
        for dd in cols:
            colno = dmDescriptorGetNo(dd)
            name  = dmGetName( dd )
            (area, field_area) = dmDescriptorGetArea( dd )
            print("%5d  %-20s %25.4lf %30.4lf" % (colno, name, area, field_area), file=self.fh)
        print("", file=self.fh)


        # close up
        try:
            ds = dmBlockGetDataset(b)
            dmBlockClose(b)
            dmDatasetClose(ds)
        except:
            raise

        # check coord axis group 
        infile  = self.indir + self.infiles[0] + "[IMGTWO]"
        try:
            b = dmImageOpen( infile )
            dd = dmImageGetDataDescriptor(b)
            print("", file=self.fh)
            print("  image file : %s" % infile, file=self.fh)
            print("  number of axis groups %2d" % dmArrayGetNoAxisGroups(dd), file=self.fh)
            gp1 = dmArrayGetAxisGroup(dd,1)
            gp2 = dmArrayGetAxisGroup(dd,2)
            print("    group 1 - name %s   desc type %s" % (dmGetName(gp1), dmDescriptorGetType(gp1)), file=self.fh)  
            print("        dmCoordGetAxisGroupNo(gp1) = %d" % dmCoordGetAxisGroupNo(gp1), file=self.fh)
            print("       ", dmCoordGetTransform(gp1), file=self.fh)
            print("    group 2 - name %s   desc type %s" % (dmGetName(gp2), dmDescriptorGetType(gp2)), file=self.fh)  
            print("        dmCoordGetAxisGroupNo(gp2) = %d" % dmCoordGetAxisGroupNo(gp2), file=self.fh)
            print("       ", dmCoordGetTransform(gp2), file=self.fh)

        except:
            raise

        # close up
        try:
            ds = dmBlockGetDataset(b)
            dmBlockClose(b)
            dmDatasetClose(ds)
        except:
            raise


        # Stress test for CoordCalc.
        # Bug_12941: memory usage buildup due to non-decremented pointers.
        print("  ", file=self.fh)
        print("  Stress Test dmCoordCalc & dmCoordInvert", file=self.fh)
        infile  = self.indir + self.infiles[0] + "[IMGONE]"
        try:
            b = dmImageOpen( infile )
            dd = dmImageGetDataDescriptor(b)
            pos = dmArrayGetAxisGroup(dd,1)
            axarr = np.array( [np.zeros( 2048 ), list(range(1,2049))], dtype=np.int64 )
            for ii in range( 2048 ):
                ip1 = ii + 1
                axarr[0].fill(ip1)
                pixels = axarr.transpose().copy()
                xy = dmCoordCalc(pos, pixels)
                ab = dmCoordInvert(pos, xy)

                if ( not np.array_equal(pixels, ab ) ):
                    print("       Bad round trip. row = %d " % (ii), file=self.fh)

            print("  Done", file=self.fh)
            print("  ", file=self.fh)

        except:
            raise


    # ----------------------------------------------------------------------
    # 
    # ----------------------------------------------------------------------
    def test_101( self ):
        """
        Testing dmBlockOpen()
                dmDatasetMoveToBlock()
        """

        print("Running Unit Test 101", file=self.fh)

        # Assign input/output file names
        infile = self.indir + self.infiles[0]

        print("  ---- Open ----", file=self.fh)
        print("  b = dmBlockOpen(<file>)", file=self.fh)
        try:
            b = dmBlockOpen( infile )
        except:
            raise
        else:
            if type(b) is dmBlock:
                print("     'b' verified as dmBlock type.", file=self.fh)
            else:
                print("     'b' is NOT a dmBlock type.", file=self.fh)
                raise Exception()

        #
        # MCD TEMP: NOTE - Add additional tests of interface.
        #

        print("  ds = dmBlockGetDataset( b )", end=' ', file=self.fh)
        try:
            ds = dmBlockGetDataset( b )
        except:
            raise
        else:
            print("... OK", file=self.fh)

        #
        # dmDatasetMoveToBlock()
        print("  ---- Move ----", file=self.fh)
        print("  img = dmDatasetMoveToBlock( b, 2 )   # Bad input arg 1 ", file=self.fh)
        try:
            img = dmDatasetMoveToBlock( b, 2 )
        except TypeError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        else:
            raise RuntimeError ("Expected failure did not occur!")

        print("  img = dmDatasetMoveToBlock( ds, b )   # Bad input arg 2 non-numeric ", file=self.fh)
        try:
            img = dmDatasetMoveToBlock( ds, b )
        except TypeError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        else:
            raise RuntimeError ("Expected failure did not occur!")

        print("  img = dmDatasetMoveToBlock( ds, 2.32 )   # Bad input arg 2 (float) ", file=self.fh)
        try:
            img = dmDatasetMoveToBlock( ds, 2.32 )
        except TypeError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        else:
            print("  OK.. this will be bad, but for now it converts", file=self.fh)
            print("  opened block %s" % dmBlockGetName( img ), file=self.fh)

        print("  img = dmDatasetMoveToBlock( ds, -1 )   # Bad input.. block number too low ", file=self.fh)
        try:
            img = dmDatasetMoveToBlock( ds, -1 )
        except IOError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        else:
            raise RuntimeError ("Expected failure did not occur!")

        print("  img = dmDatasetMoveToBlock( ds, 100 )   # Bad input.. block number too high ", file=self.fh)
        try:
            img = dmDatasetMoveToBlock( ds, 100 )
        except IOError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        else:
            raise RuntimeError ("Expected failure did not occur!")

        print("  img = dmDatasetMoveToBlock( ds, 3 )   # Good. ", file=self.fh)
        try:
            img = dmDatasetMoveToBlock( ds, 3 )
        except:
            raise
        else:
            print("  opened block %s" % dmBlockGetName( img ), file=self.fh)


        print("  ---- Close ----", file=self.fh)
        # close the block 
        print("  dmBlockClose( b )", end=' ', file=self.fh)
        try:
            dmBlockClose( b )
        except:
            raise
        else:
            print("... OK", file=self.fh)

        print("  dmBlockClose( img )", end=' ', file=self.fh)
        try:
            dmBlockClose( img )
        except:
            raise
        else:
            print("... OK", file=self.fh)

        # close the dataset 
        print("  dmDatasetClose( ds )", end=' ', file=self.fh)
        try:
            dmDatasetClose(ds)
        except:
            raise
        else:
            print("... OK", file=self.fh)



    # ----------------------------------------------------------------------
    #
    # ----------------------------------------------------------------------
    def test_102( self ):
        """
           This is checking memory handling..
           Its effects are not visible without a print statement in the
           dmBlock_dealloc() function... 
        """
        print("Running Unit Test 102", file=self.fh)

        # Assign input/output file names
        infile = self.indir + self.infiles[0]

        # open the block 
        print("  b = dmBlockOpen(<file>)", file=self.fh)
        try:
            b = dmBlockOpen( infile )
        except:
            raise
        else:
            if type(b) is dmBlock:
                print("     'b' verified as dmBlock type.", file=self.fh)
            else:
                print("     'b' is NOT a dmBlock type.", file=self.fh)
                raise Exception()
        
        print("  Make another reference to this block", file=self.fh)
        print("  spare = b", file=self.fh)
        spare = b
        
        # close the block 
        print("  dmBlockClose( b ).. should not call pyBlock_dealloc()", end=' ', file=self.fh)
        try:
            dmBlockClose( b )
        except:
            raise
        else:
            print("... OK", file=self.fh)


        print("  reassign extra reference.. should dealloc pyBlock", file=self.fh)
        print("  spare = 7", file=self.fh)
        spare = 7


    # ----------------------------------------------------------------------
    #
    # ----------------------------------------------------------------------
    def test_103( self ):
        """
           This is checking memory handling..
           Open a block, open another block using same variable, close block
             - The second open drops the only reference to the open block
               so it should call the dmBlock dealloc function.
        """
        print("Running Unit Test 103", file=self.fh)

        # Assign input/output file names
        infile1 = self.indir + self.infiles[0]
        infile2 = self.indir + self.infiles[1]

        print("  ds = dmDatasetOpen(<file>)", file=self.fh)
        try:
            ds = dmDatasetOpen( infile1 )
        except:
            raise

        if dmIsEmpty( ds ) == False and type(ds) is dmDataset:
            print("     'ds' verified as non-empty dmDataset type.", file=self.fh)
        else:
            print("     'ds' is either empty or NOT a dmDataset type.", file=self.fh)
            raise Exception()
    
        print("  dmDatasetClose( ds )", end=' ', file=self.fh)
        try:
            dmDatasetClose(ds)
        except:
            raise
        else:
            print("... OK", file=self.fh)

        # open the block 
        print("  b = dmBlockOpen(<file>)", file=self.fh)
        try:
            b = dmBlockOpen( infile1 )
        except:
            raise
        
        print("  b = dmBlockOpen(<otherfile>)", file=self.fh)
        print("      expect to see pyBlock_dealloc() called for first block.", file=self.fh)
        try:
            b = dmBlockOpen( infile2 )
        except:
            raise
        
        # close the block 
        print("  dmBlockClose( b )", file=self.fh)
        print("    expect to see pyBlock_dealloc() called for second block.", file=self.fh)
        try:
            dmBlockClose( b )
        except:
            raise


    # ----------------------------------------------------------------------
    #
    # ----------------------------------------------------------------------
    def test_104( self ):
        """
        dmColumnCreate()
           NOTE: Run test_6 first to create table used here
        """
        # Assign input/output file names
        outfile = self.outdir + self.outfiles[0]

        # check if outfile exists.. if not, run test_6
        if not os.path.isfile( outfile ):
            print("  Input file from test_6 not available.. generating", file=self.fh)
            self.test_6()
            print("  Input file generated.. continue", file=self.fh)
            print("", file=self.fh)

        print("Running Unit Test 104", file=self.fh)

        # Open the table block for update
        print("  dmTableOpen( outfile, update=True )", file=self.fh)
        tab = dmTableOpen( outfile, update=True)

        # Column Create.. interface
        print("  d = dmDescriptor()", file=self.fh)
        d = dmDescriptor()
        print("", file=self.fh)

        dims = np.array([5], dtype=np.int32)

        print("  col = dmColumnCreate( d )                                       # bad input for arg1", file=self.fh)
        try:
            col = dmColumnCreate( d )
        except TypeError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise

        print("  col = dmColumnCreate( tab )                                     # missing input for arg2+", file=self.fh)
        try:
            col = dmColumnCreate( tab )
        except TypeError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise

        print("  col = dmColumnCreate( tab , 1 )                                 # bad input for arg2", file=self.fh)
        try:
            col = dmColumnCreate( tab, 1 )
        except TypeError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise

        print("  col = dmColumnCreate( tab, \"JCOL\" )                             # missing input for arg3+", file=self.fh)
        try:
            col = dmColumnCreate( tab, b"JCOL" )
        except TypeError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise

        print("  col = dmColumnCreate( tab, \"JCOL\", d )                          # bad input for arg2", file=self.fh)
        try:
            col = dmColumnCreate( tab, "JCOL", d )
        except TypeError as e:
            if "Cannot interpret '<dmDescriptor object" in str(e):
                print("     Cannot interpret '<dmDescriptor object> as a data type", file=self.fh)
            else:
                print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise

        print("  col = dmColumnCreate( tab, \"SCOL\", np.string_ )                 # missing itemsize (string)", file=self.fh)
        try:
            col = dmColumnCreate( tab, "SCOL", np.string_ )
        except ValueError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise

        print("  col = dmColumnCreate( tab, \"IVEC\", np.short, cptnames=[2] )     # bad vector input (short)", file=self.fh)
        try:
            col = dmColumnCreate( tab, "IVEC", np.short, cptnames=[2] )
        except ValueError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise

        # test multiple column interface

        print('col = dmColumnCreate( tab, ["ICOL1", "ICOL2"], np.short ) # bad number of data types', file=self.fh)
        try:
            col = dmColumnCreate( tab, ["ICOL1", "ICOL2"], np.short )
        except AttributeError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise

        print('col = dmColumnCreate( tab, ["DCOL1", "DCOL2"], [np.float64, np.float64, np.float32] ) # bad - too many data types', file=self.fh)
        try:
            col = dmColumnCreate( tab, ["DCOL1", "DCOL2"], [np.float64, np.float64, np.float32] )
        except AttributeError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise


        print('col = dmColumnCreate( tab, ["DCOL1", "DCOL2"], [np.float64, np.float64], itemsize=[10,10,10], unit=["m", "nm"]   # bad - too many items sizes', file=self.fh)
        try:
            col = dmColumnCreate( tab, ["DCOL1", "DCOL2"], [np.float64, np.float64], itemsize=[10,10,10], unit=["m", "nm"]  )
        except AttributeError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise


        print('col = dmColumnCreate( tab, ["DCOL1", "DCOL2"], [np.float64, np.float64], unit=["nm","m","ft"]  ) # bad - too many units', file=self.fh)
        try:
            col = dmColumnCreate( tab, ["DCOL1", "DCOL2"], [np.float64, np.float64], unit=["nm","m","ft"]  )
        except AttributeError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise

        print('col = dmColumnCreate( tab, ["DCOL1", "DCOL2"], [np.float64, np.float64], desc=["test","test2","test3"] ) # bad - too many descriptions', file=self.fh)
        try:
            col = dmColumnCreate( tab, ["DCOL1", "DCOL2"], [np.float64, np.float64], desc=["test","test2","test3"]  )
        except AttributeError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise

        print('col = dmColumnCreate( tab, ["DVEC1", "DVEC2"], [np.float64, np.float64], cptnames=[["DV1","DV2","DV3"],"DV1","DV2"] ) # bad - too many cptnames', file=self.fh)
        try:
            col = dmColumnCreate( tab, ["DVEC1", "DVEC2"], [np.float64, np.float64], cptnames=[["DV1","DV2","DV3"],"DV1","DV2"]  )
        except AttributeError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise

        print('col = dmColumnCreate( tab, ["DCOL1", "DCOL2"], [np.float64, np.float64], shape=[dims,dims,dims] )  # bad - too many shapes', file=self.fh)
        try:
            col = dmColumnCreate( tab, ["DCOL1", "DCOL2"], [np.float64, np.float64], shape=[dims,dims,dims] )
        except AttributeError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
    

        # close up
        try:
            print("  dmTableClose( tab )", file=self.fh)
            dmTableClose(tab)
        except:
            raise



    # ----------------------------------------------------------------------
    #
    # ----------------------------------------------------------------------
    def test_105( self ):
        """
        Testing dmTableColumnOpen()

        NOTE: Expects test_5 (Block Copy) to have been run
        """

        # Assign input/output file names
        outfile  = self.outdir + self.outfiles[1]

        # check if outfile exists.. if not, run test_5
        if not os.path.isfile( outfile ):
            print("  Input file from test_5 not available.. generating", file=self.fh)
            self.test_5()
            print("  Input file generated.. continue", file=self.fh)
            print("", file=self.fh)


        print("Running Unit Test 105", file=self.fh)

        print("  b = dmBlockOpen(<file>, update=True)", file=self.fh)
        try:
            b = dmBlockOpen( outfile, update=True )
        except:
            raise

        print("  d = dmDescriptor()", file=self.fh)
        d = dmDescriptor()
        print("", file=self.fh)

        print("# ----------------------------------------------------------------------", file=self.fh)
        print("# Column Handling", file=self.fh)
        print("# ----------------------------------------------------------------------", file=self.fh)
        try:
            print("  col = dmTableColumnOpen( d , d )                 # bad input for arg1", file=self.fh)
            a = dmTableOpenColumn( d, d )
        except TypeError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise

        try:
            print("  col = dmTableColumnOpen( b , d )               # bad input for arg2", file=self.fh)
            a = dmTableOpenColumn( b, d )
        except TypeError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise

        try:
            print("  col = dmTableColumnOpen( b , 0 )                # bad input for arg2", file=self.fh)
            a = dmTableOpenColumn( b, 0 )
        except ValueError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise

        try:
            print("  col = dmTableColumnOpen( b , 100 )              # bad input for arg2 ", file=self.fh)
            a = dmTableOpenColumn( b, 100 )
        except Exception as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise

        try:
            print("  col = dmTableColumnOpen( b , 4 )                # good input - by column number", file=self.fh)
            c1 = dmTableOpenColumn( b, 4 )
        except:
            raise

        if dmIsEmpty(c1) == False and type(c1) is dmDescriptor:
            print("     'col' verified as non-empty dmDescriptor type.", file=self.fh)
        else:
            print("     'col' is either empty or NOT a dmDescriptor type.", file=self.fh)
            raise Exception()


        try:
            print("  col = dmTableColumnOpen( b , \"scol\" )    # good input - by column name", file=self.fh)
            c2 = dmTableOpenColumn( b, "scol" )
        except:
            raise

        if dmIsEmpty(c2) == False and type(c2) is dmDescriptor:
            print("     'col' verified as non-empty dmDescriptor type.", file=self.fh)
        else:
            print("     'col' is either empty or NOT a dmDescriptor type.", file=self.fh)
            raise Exception()
        

        print("  dmBlockClose( b )", file=self.fh)
        # close up
        try:
            ds = dmBlockGetDataset(b)
            dmBlockClose(b)
            dmDatasetClose(ds)
        except:
            raise


    # ----------------------------------------------------------------------
    # 
    # ----------------------------------------------------------------------
    def test_106( self ):
        """
        Testing dmKeyOpen(), dmKeyRead(), dmKeyWrite()

        NOTE: Expects test_5 (Block Copy) to have been run
        """

        # Assign input/output file names
        outfile  = self.outdir + self.outfiles[1]

        # check if outfile exists.. if not, run test_5
        if not os.path.isfile( outfile ):
            print("  Input file from test_5 not available.. generating", file=self.fh)
            self.test_5()
            print("  Input file generated.. continue", file=self.fh)
            print("", file=self.fh)

        print("Running Unit Test 106", file=self.fh)

        print("  b = dmBlockOpen(<file>, update=True)", file=self.fh)
        try:
            b = dmBlockOpen( outfile, update=True )
        except:
            raise

        print("  d = dmDescriptor()", file=self.fh)
        d = dmDescriptor()
        print("", file=self.fh)
    
        print("# ----------------------------------------------------------------------", file=self.fh)
        print("# Keyword Handling", file=self.fh)
        print("# ----------------------------------------------------------------------", file=self.fh)
        print("  k = dmKeyOpen( d )              # bad input for arg1", file=self.fh)
        try:
            k = dmKeyOpen( d )
        except TypeError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
    
        print("  k = dmKeyOpen( b )              # missing input for arg2", file=self.fh)
        try:
            k = dmKeyOpen( b )
        except TypeError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
    
        print("  k = dmKeyOpen( b , 1 )          # bad input for arg2", file=self.fh)
        try:
            k = dmKeyOpen( b , 1 )
        except TypeError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
    
        print("  k = dmKeyOpen( b , \"BLAH\")      # non-existent key", file=self.fh)
        try:
            k = dmKeyOpen( b , "BLAH")
        except TypeError as e:
            print("    ", e, file=self.fh)
            print("     Unexpected...", file=self.fh)
            raise
        except ValueError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
    
        print("  k = dmKeyOpen( b , \"SVALKEY\")   # good key", file=self.fh)
        try:
            k = dmKeyOpen( b , b"SVALKEY")
        except:
            raise
    

        del k

        print("  (k,v) = dmKeyRead(d, \"HISTNUM\")  # bad input for arg1", file=self.fh)
        try:
            (k,v) = dmKeyRead(d, "HISTNUM")
        except TypeError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        
        print("  (k,v) = dmKeyRead( b )             # missing input for arg2", file=self.fh)
        try:
            (k,v) = dmKeyRead( b )
        except TypeError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        
        print("  (k,v) = dmKeyRead( b , 1 )         # bad input for arg2", file=self.fh)
        try:
            (k,v) = dmKeyRead( b , 1 )
        except TypeError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
    
        print("  (k,v) = dmKeyRead( b , \"BLAH\")      # non-existent key", file=self.fh)
        try:
            (k,v) = dmKeyRead( b , "BLAH")
        except TypeError as e:
            print("    ", e, file=self.fh)
            print("     Unexpected...", file=self.fh)
            raise
        except ValueError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise

        # Successful read of numerical keyword
        print("  (k,v) = dmKeyRead(b, \"HISTNUM\", dtype=np.short)   # successful numeric key", file=self.fh)
        try:
            (k,v) = dmKeyRead(b, b"HISTNUM", dtype=np.short)
            if self._check_datatype(v, np.short):
                print("      v datatype verified.", file=self.fh)
            if self._check_value( v, np.short(24) ):
                print("      v value verified.", file=self.fh)
        except:
            raise


        # input Bad datatype
        print("  (k,v) = dmKeyRead(b, \"HISTNUM\", dtype=dmBlock)    # bad input datatype", file=self.fh)
        try:
            (k,v) = dmKeyRead(b, "HISTNUM", dtype=dmBlock)
        except ValueError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise

        # input Bad conversion
        print("  (k,v) = dmKeyRead(b, \"HISTNUM\", dtype=np.string_) # bad conversion request", file=self.fh)
        try:
            (k,v) = dmKeyRead(b, "HISTNUM", dtype=np.string_)
        except ValueError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise


        # Successful read of string keyword
        print("  (k,v) = dmKeyRead(b, \"SVALKEY\", dtype=np.string_) # successful string key", file=self.fh)
        try:
            (k,v) = dmKeyRead(b, "SVALKEY", dtype=np.string_)
            if self._check_datatype(v, np.string_):
                print("      v datatype verified.", file=self.fh)
            if self._check_value( v, np.string_("NOVA") ):
                print("      v value verified.", file=self.fh)
        except:
            raise


        # Successful conversion
        print("  (k,v) = dmKeyRead(b, \"SNUMKEY\", dtype=np.int)     # successful conversion request", file=self.fh)
        try:
            (k,v) = dmKeyRead(b, "SNUMKEY", dtype=np.int64)
            if self._check_datatype(v, np.int64):
                print("      v datatype verified.", file=self.fh)
            if self._check_value( v, np.int64(666) ):
                print("      v value verified.", file=self.fh)
        except:
            raise


        del k
        del v

        print("  k = dmKeyWrite(d, \"HISTNUM\")  # bad input for arg1", file=self.fh)
        try:
            k = dmKeyWrite(d, "HISTNUM")
        except TypeError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
    
        print("  k = dmKeyWrite( b )             # missing input for arg2", file=self.fh)
        try:
            k = dmKeyWrite( b )
        except TypeError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
    
        print("  k = dmKeyWrite( b , 1 )         # bad input for arg2", file=self.fh)
        try:
            k = dmKeyWrite( b , 1 )
        except TypeError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise


        print("  dmBlockClose( b )", file=self.fh)
        # close up
        try:
            ds = dmBlockGetDataset(b)
            dmBlockClose(b)
            dmDatasetClose(ds)
        except:
            raise

        k2 = None
        print("  k2 = dmKeyOpen( b , \"TELESCOP\") # using empty block ", file=self.fh)
        try:
            k2 = dmKeyOpen( b , "TELESCOP")
        except Exception as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass


    # ----------------------------------------------------------------------
    #
    # ----------------------------------------------------------------------
    def test_107( self ):
        """
        dmGetVersion 
        dmIsEmpty
        """
        print("Running Unit Test 107", file=self.fh)

        try:
            vers = dmGetVersion()
        except:
            raise
        
        print("   dmGetVersion() = '%s'" % vers, file=self.fh)  
        print("", file=self.fh)
        

        # Assign input/output file names
        infile  = self.indir + self.infiles[0]

        try:
            num = 8
            print("  dmIsEmpty(num)                     # check non DM type", file=self.fh)
            res = dmIsEmpty(num)
        except TypeError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise

        print("  b = dmBlock()                      # define empty block struct", file=self.fh)
        b = dmBlock()
        try:
            print("  dmIsEmpty(b)                       # check empty block struct", file=self.fh)
            res = dmIsEmpty(b)
        except:
            raise

        if res is True:
            print("     'b' verified empty.", file=self.fh)
        else:
            print("     'b' verified NOT empty.", file=self.fh)
            raise Exception()

        print("  b = dmBlockOpen(infile)            # fill block struct", file=self.fh)
        b = dmBlockOpen(infile)
        try:
            print("  dmIsEmpty(b)                       # check full block struct", file=self.fh)
            res = dmIsEmpty(b)
        except:
            raise

        if res is False:
            print("     'b' verified NOT empty.", file=self.fh)
        else:
            print("     'b' verified empty.", file=self.fh)
            raise Exception()

        print("  d = dmDescriptor()                 # define empty descriptor struct", file=self.fh)
        d = dmDescriptor()
        try:
            print("  dmIsEmpty(d)                       # check empty descriptor struct", file=self.fh)
            res = dmIsEmpty(d)
        except:
            raise

        if res is True:
            print("     'd' verified empty.", file=self.fh)
        else:
            print("     'd' verified NOT empty.", file=self.fh)
            raise Exception()

        print("   (k,v) = dmKeyRead(b,\"HISTNUM\")    # fill descriptor", file=self.fh)
        (k,v) = dmKeyRead(b,"HISTNUM")
    
        try:
            print("  dmIsEmpty(k)                       # check full descriptor struct", file=self.fh)
            res = dmIsEmpty(k)
        except:
            raise

        if res is False:
            print("     'k' verified NOT empty.", file=self.fh)
        else:
            print("     'k' verified empty.", file=self.fh)
            raise Exception()

        # close up
        try:
            ds = dmBlockGetDataset(b)
            dmBlockClose(b)
            dmDatasetClose(ds)
        except:
            raise

    # ----------------------------------------------------------------------
    #
    # ----------------------------------------------------------------------
    def test_108( self ):
        """
        dmTableOpen()
        """
        print("Running Unit Test 108", file=self.fh)

        # Assign input/output file names
        infile  = self.indir + self.infiles[0]

        # open the Table 
        print("  b = dmTableOpen(<file>)", file=self.fh)
        try:
            b = dmTableOpen( infile )
        except:
            raise
        else:
            if type(b) is dmBlock:
                print("     'b' verified as dmBlock type.", file=self.fh)
            else:
                print("     'b' is NOT a dmBlock type.", file=self.fh)
                raise Exception()

        # check that the block is a dmTABLE
        print("  btype = dmBlockGetType( b )", file=self.fh)
        try:
            btype = dmBlockGetType( b )
        except:
            raise
        else:
            if type(btype) is dmBlockType:
                print("     'btype' verified as dmBlockType type.", file=self.fh)
            else:
                print("     'btype' is NOT a dmBlockType type.", file=self.fh)
                raise Exception()

        if btype == dmTABLE:
            print("     Block type = %s" % btype, file=self.fh)
        else:
            print("     Block type is NOT dmTABLE... Error", file=self.fh)
            raise Exception()

        
        # close up
        try:
            print("  dmTableClose( b )", file=self.fh)
            dmTableClose(b)
        except:
            raise


    # ----------------------------------------------------------------------
    #
    # ----------------------------------------------------------------------
    def test_109( self ):
        """
        dmImageOpen
        dmImageGetDataDescriptor
        """

        print("Running Unit Test 109", file=self.fh)

        # Assign input/output file names
        infile  = self.indir + self.infiles[1]

        # open the Image 
        print("  b = dmImageOpen(<file>)", file=self.fh)
        try:
            b = dmImageOpen( infile )
        except:
            raise
        else:
            if type(b) is dmBlock:
                print("     'b' verified as dmBlock type.", file=self.fh)
            else:
                print("     'b' is NOT a dmBlock type.", file=self.fh)
                raise Exception()

        # check that the block is a dmImage
        print("  btype = dmBlockGetType( b )", file=self.fh)
        try:
            btype = dmBlockGetType( b )
        except:
            raise

        if btype == dmIMAGE:
            print("     Block type = %s" % btype, file=self.fh)
        else:
            print("     Block type is NOT dmIMAGE... Error", file=self.fh)
            raise Exception()


        print("  dd = dmImageGetDataDescriptor(b)", file=self.fh)
        try:
            dd = dmImageGetDataDescriptor(b)
        except:
            raise

        if dmIsEmpty(dd) == False and type(dd) is dmDescriptor:
            print("     'dd' verified as non-empty dmDescriptor type.", file=self.fh)
        else:
            print("     'dd' is either empty or NOT a dmDescriptor type.", file=self.fh)
            raise Exception()


        
        # close up
        try:
            print("  dmBlockGetDataset( b )", file=self.fh)
            ds = dmBlockGetDataset(b)
            print("  dmBlockClose( b )", file=self.fh)
            dmBlockClose(b)
            print("  dmDatasetClose( ds )", file=self.fh)
            dmDatasetClose(ds)
        except:
            raise


    # ----------------------------------------------------------------------
    #
    # ----------------------------------------------------------------------
    def test_110( self ):
        """
        dmArrayGetAxisGroup
        dmGetArrayDimensions
        dmDescriptorGetCoord
        
        """
        print("Running Unit Test 110", file=self.fh)
        
        # Assign input/output file names
        infile1 = self.indir + self.infiles[1]
        infile2 = self.indir + self.infiles[0]

        expected_dims = np.array ([3,5])
        expected_arcol_dims = 5

        # open the Table
        t = dmTableOpen ( infile2 )
        arcol_dd = dmTableOpenColumn (t, "facol")
        vir_dd  = dmTableOpenColumn (t, "sky")

        # open the Image
        try:
            b = dmImageOpen( infile1 )
            dd = dmImageGetDataDescriptor(b)
        except:
            raise
            
        print("  dims = dmGetArrayDimensions (dd)   #image", file=self.fh)
        try:
            dims = dmGetArrayDimensions (dd)
        except:
            raise
        else:
            for ii in dims == expected_dims:
                if not ii:
                    print("     array dims do NOT match", file=self.fh)
                    print("     expected dim: ",expected_dims, file=self.fh)
                    print("     actual dim: ",dims, file=self.fh);
                    raise Exception ()
                else:
                    print("     dims pass", file=self.fh)

        print("  dims = dmGetArrayDimensions (arcol_dd)  #table", file=self.fh)
        try:
            dims = dmGetArrayDimensions (arcol_dd)
        except:
            raise
        else:
            for ii in dims == expected_arcol_dims:
                if not ii:
                    print("     array dims do NOT match", file=self.fh)
                    print("     expected dim: ",expected_arcol_dims, file=self.fh)
                    print("     actual dim: ",dims, file=self.fh);
                    raise Exception ()
                else:
                    print("     dims pass", file=self.fh)


        print("  ax_dd = dmArrayGetAxisGroup (dd,10)    #bad check", file=self.fh)
        try:
            ax_dd = dmArrayGetAxisGroup (dd,10)
        except Exception as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)


        print("  ax_dd = dmArrayGetAxisGroup (dd,1)   #good check", file=self.fh)
        try:
            ax_dd = dmArrayGetAxisGroup (dd,1)
        except:
            raise
        else:
            if type(ax_dd) is dmDescriptor:
                print("     'ax_dd' verified as dmDescriptor type.", file=self.fh)
            else:
                print("     'ax_dd' is NOT a dmDescriptor type.", file=self.fh)
                raise Exception()

            # check that the descriptor is set
            print("  descriptor name: %s"%(dmGetName (ax_dd)), file=self.fh)

        print("  coord_dd = dmDescriptorGetCoord (ax_dd)    # image axis", file=self.fh)
        try:
            coord_dd = dmDescriptorGetCoord (ax_dd)
        except:
            raise
        else:
            if type(coord_dd) is dmDescriptor:
                print("     'coord_dd' verified as dmDescriptor type.", file=self.fh)
            else:
                print("     'coord_dd' is NOT a dmDescriptor type.", file=self.fh)
                raise Exception()

            # check that the descriptor is set
            print("  coord descriptor name: %s"%(dmGetName (coord_dd)), file=self.fh)

        print("  coord_dd = dmDescriptorGetCoord (vir_dd)    #table column", file=self.fh)
        try:
            coord_dd = dmDescriptorGetCoord (vir_dd)
        except:
            raise
        else:
            if type(coord_dd) is dmDescriptor:
                print("     'coord_dd' verified as dmDescriptor type.", file=self.fh)
            else:
                print("     'coord_dd' is NOT a dmDescriptor type.", file=self.fh)
                raise Exception()

            # check that the descriptor is set
            print("  coord descriptor name: %s"%(dmGetName (coord_dd)), file=self.fh)

        print("  coord_dd = dmDescriptorGetCoord (vir_dd, 1)", file=self.fh)
        try:
            coord_dd = dmDescriptorGetCoord (vir_dd, 1)
        except:
            raise
        else:
            if type(coord_dd) is dmDescriptor:
                print("     'coord_dd' verified as dmDescriptor type.", file=self.fh)
            else:
                print("     'coord_dd' is NOT a dmDescriptor type.", file=self.fh)
                raise Exception()

            # check that the descriptor is set
            print("  coord descriptor name: %s"%(dmGetName (coord_dd)), file=self.fh)

        print("  coord_dd = dmDescriptorGetCoord (vir_dd, coordno=1)", file=self.fh)
        try:
            coord_dd = dmDescriptorGetCoord (vir_dd, coordno=1)
        except:
            raise
        else:
            if type(coord_dd) is dmDescriptor:
                print("     'coord_dd' verified as dmDescriptor type.", file=self.fh)
            else:
                print("     'coord_dd' is NOT a dmDescriptor type.", file=self.fh)
                raise Exception()

            # check that the descriptor is set
            print("  coord descriptor name: %s"%(dmGetName (coord_dd)), file=self.fh)

            print("  coord_dd = dmDescriptorGetCoord (vir_dd, 2)    #bad check", file=self.fh)
            try:
                coord_dd = dmDescriptorGetCoord (vir_dd, 2)
            except Exception as e:
                print("    ", e, file=self.fh)
                print("     Expected ... OK", file=self.fh)

        print("  coord_dd = dmDescriptorGetCoord (vir_dd, coord=1)    #bad check", file=self.fh)
        try:
            coord_dd = dmDescriptorGetCoord (vir_dd, coord=1)
        except Exception as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)


    # ----------------------------------------------------------------------
    #
    # ----------------------------------------------------------------------
    def test_111( self ):
        """
        dmGetData
        
        """

        print("Running Unit Test 111", file=self.fh)

        # Assign input/output file names
        infile1 = self.indir + self.infiles[1] # image
        infile2 = self.indir + self.infiles[0] # table
        infile3 = self.indir + self.infiles[8]+'[2]' # varlen scalar
        infile4 = self.indir + self.infiles[8]+'[3]' # varlen scalar

        # open the Table
        t = dmTableOpen ( infile2 )
        scol_dd = dmTableOpenColumn (t, "scol")
        jcol_dd = dmTableOpenColumn (t, "jcol")
        lcol_dd = dmTableOpenColumn (t, "lcol")
        bcol_dd = dmTableOpenColumn (t, "bcol")
        dacol_dd = dmTableOpenColumn (t, "dacol")
        sky_dd = dmTableOpenColumn (t, "sky")

        # open the Image
        i = dmImageOpen( infile1 )
        img_dd = dmImageGetDataDescriptor(i)

        # open varlen scalar file
        v = dmTableOpen( infile3 )

        for ii in range (1,7):
            varlen_dd = dmTableOpenColumn (v, "VSCAL"+str(ii))

            print("  data = dmGetData (VSCAL"+ str(ii) + "), nrows=6)", file=self.fh)
            try:
                data = dmGetData (varlen_dd, nrows=6)
            except:
                raise
            else:
                print(data, file=self.fh)


        # open varlen vector file
        vvec = dmTableOpen( infile4 )

        for ii in range (1,7):
            varvec_dd = dmTableOpenColumn (vvec, "VVECT"+str(ii))

            print("  data = dmGetData (VVECT"+ str(ii) + "), nrows=6)", file=self.fh)
            try:
                data = dmGetData (varvec_dd, nrows=6)
            except:
                raise
            else:
                print(data, file=self.fh)

        print("  data = dmGetData (scol_dd)", file=self.fh)
        try:
            data = dmGetData (scol_dd)  # scalar
        except:
            raise
        else:
            print(data, file=self.fh)
        
        print("  data = dmGetData (jcol_dd)", file=self.fh)
        try:
            data = dmGetData (jcol_dd)
        except:
            raise
        else:
            print(data, file=self.fh)

        print("  data = dmGetData (lcol_dd)", file=self.fh)
        try:
            data = dmGetData (lcol_dd)
        except:
            raise
        else:
            print(data, file=self.fh)

        print("  data = dmGetData (bcol_dd)", file=self.fh)
        try:
            data = dmGetData (bcol_dd)
        except:
            raise
        else:
            print(data, file=self.fh)

        print("  data = dmGetData (dacol_dd)", file=self.fh)
        try:
            data = dmGetData (dacol_dd)
        except:
            raise
        else:
            print(data, file=self.fh)

        print("  data = dmGetData (sky_dd)", file=self.fh)
        try:
            data = dmGetData (sky_dd)
        except:
            raise
        else:
            print(data, file=self.fh)

        # multiple rows
        print("  data = dmGetData (scol_dd, nrows=2)", file=self.fh)
        try:
            data = dmGetData (scol_dd, nrows=2)
        except:
            raise
        else:
            print(data.astype(self._stype), file=self.fh)

        print("  data = dmGetData (jcol_dd, nrows=2)", file=self.fh)
        try:
            data = dmGetData (jcol_dd, nrows=2)
        except:
            raise
        else:
            print(data, file=self.fh)

        print("  data = dmGetData (lcol_dd, nrows=4)", file=self.fh)
        try:
            data = dmGetData (lcol_dd, nrows=4)
        except:
            raise
        else:
            print(data, file=self.fh)

        print("  data = dmGetData (bcol_dd, nrows=2)", file=self.fh)
        try:
            data = dmGetData (bcol_dd, nrows=2)
        except:
            raise
        else:
            print(data, file=self.fh)

        print("  data = dmGetData (dacol_dd, nrows=2)", file=self.fh)
        try:
            data = dmGetData (dacol_dd, nrows=2)
        except:
            raise
        else:
            print(data, file=self.fh)

        print("  data = dmGetData (sky_dd, nrows=3)", file=self.fh)
        try:
            data = dmGetData (sky_dd, nrows=3)
        except:
            raise
        else:
            print(data, file=self.fh)

        #select row
        print("  data = dmGetData (scol_dd, 2,2)", file=self.fh)
        try:
            data = dmGetData (scol_dd, 2,2)
        except:
            raise
        else:
            print(data.astype(self._stype), file=self.fh)

        print("  data = dmGetData (jcol_dd, 3)", file=self.fh)
        try:
            data = dmGetData (jcol_dd, 3)
        except:
            raise
        else:
            print(data, file=self.fh)

        print("  data = dmGetData (lcol_dd, rowno=4)", file=self.fh)
        try:
            data = dmGetData (lcol_dd, rowno=4)
        except:
            raise
        else:
            print(data, file=self.fh)

        print("  data = dmGetData (dacol_dd, 2)", file=self.fh)
        try:
            data = dmGetData (dacol_dd, 2)
        except:
            raise
        else:
            print(data, file=self.fh)

        print("  data = dmGetData (sky_dd, 2,3)", file=self.fh)
        try:
            data = dmGetData (sky_dd, 2,3)
        except:
            raise
        else:
            print(data, file=self.fh)

        # data from image
        print("  data = dmGetData (img_dd)", file=self.fh)
        try:
            data = dmGetData (img_dd)
        except:
            raise
        else:
            print(data, file=self.fh)

        print("  data = dmGetData (img_dd, 1, 1)", file=self.fh)
        try:
            data = dmGetData (img_dd, 1, 1)
        except:
            raise
        else:
            print(data, file=self.fh)

        # error checking
        print("  data = dmGetData (lcol_dd, 1,2,3)", file=self.fh)
        try:
            data = dmGetData (lcol_dd, 1,2,3)
        except TypeError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        else:
            raise RuntimeError ("     Unexpected Pass ... FAIL")

        print("  data = dmGetData ()", file=self.fh)
        try:
            data = dmGetData ()
        except TypeError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        else:
            raise RuntimeError ("     Unexpected Pass ... FAIL")

        print("  data = dmGetData (lcol_dd, nrow=1)", file=self.fh)
        try:
            data = dmGetData (lcol_dd, nrow=1)
        except TypeError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        else:
            raise RuntimeError ("     Unexpected Pass ... FAIL")

        print("  data = dmGetData (lcol_dd, rown=1)", file=self.fh)
        try:
            data = dmGetData (lcol_dd, rown=1)
        except TypeError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        else:
            raise RuntimeError ("     Unexpected Pass ... FAIL")

        print("  data = dmGetData (lcol_dd, nrows=10)", file=self.fh)
        try:
            data = dmGetData (lcol_dd, nrows=10)
        except ValueError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        else:
            raise RuntimeError ("     Unexpected Pass ... FAIL")


        print("  data = dmGetData (lcol_dd, 10)", file=self.fh)
        try:
            data = dmGetData (lcol_dd, 10)
        except ValueError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        else:
            raise RuntimeError ("     Unexpected Pass ... FAIL")


        print("  data = dmGetData (sky_dd, -1)", file=self.fh)
        try:
            data = dmGetData (sky_dd, -1)
#        except TypeError as e:
#            print >> self.fh, "    ", e
#            print >> self.fh, "     Expected ... OK"
#            pass
        except:
            raise
        else:
            print("     This should be an error ??", file=self.fh)
#            raise RuntimeError ("     Unexpected Pass ... FAIL")

        # Bug 13365 - side effect issue reading empty key with dmGetData()
        key = dmKeyOpen(t, "EMTYKEY")
        print("  data = dmGetData ( key )", file=self.fh)
        try:
            data = dmGetData( key )
        except:
            raise
        else:
            print(data.astype(self._stype), file=self.fh)




    # ----------------------------------------------------------------------
    #
    # ----------------------------------------------------------------------
    def test_112( self ):
        """
        dmSetData

        """

        print("Running Unit Test 112", file=self.fh)

        # Assign input/output file names
        infile1 = self.indir + self.infiles[1] # image
        infile2 = self.indir + self.infiles[0] # table
        infile3 = self.indir + self.infiles[8] + '[2]' # varlen table columns
        infile4 = self.indir + self.infiles[8] + '[3]' # varlen vector table columns


        # open the Table
        t = dmTableOpen ( infile2 )
        scol_dd = dmTableOpenColumn (t, "scol")
        jcol_dd = dmTableOpenColumn (t, "jcol")
        lcol_dd = dmTableOpenColumn (t, "lcol")
        bcol_dd = dmTableOpenColumn (t, "bcol")
        dacol_dd = dmTableOpenColumn (t, "dacol")
        sky_dd = dmTableOpenColumn (t, "sky")

        # open the Image
        i = dmImageOpen( infile1 )
        img_dd = dmImageGetDataDescriptor(i)

        print("  dmSetData (scol_dd, 'dog')", file=self.fh)
        try:
            dmSetData (scol_dd, 'dog')
        except:
            raise
        else:
            vals = dmGetData(scol_dd, nrows=4)
            print(vals.astype(self._stype), file=self.fh)

        print("  dmSetData (jcol_dd, 5)", file=self.fh)
        try:
            dmSetData (jcol_dd, 5)
        except:
            raise
        else:
            print(dmGetData (jcol_dd, nrows=4), file=self.fh)

        print("  dmSetData (bcol_dd, 0b0101)", file=self.fh)
        try:
            dmSetData (bcol_dd, 0b0101)
        except:
            raise
        else:
            print(dmGetData (bcol_dd,nrows=4), file=self.fh)

        print("  dmSetData (dacol_dd, [100.001, 100.002, 100.003, 100.004])", file=self.fh)
        try:
            dmSetData (dacol_dd, [100.001, 100.002, 100.003, 100.004])
        except:
            raise
        else:
            print(dmGetData (dacol_dd,nrows=4), file=self.fh)

        print("  dmSetData (sky_dd, [4,5])", file=self.fh)
        try:
            dmSetData (sky_dd, [4,5])
        except:
            raise
        else:
            print(dmGetData (sky_dd,nrows=4), file=self.fh)

        # multiple rows
        print("  dmSetData (scol_dd, ['bird','','cat'])", file=self.fh)
        try:
            dmSetData (scol_dd, ['bird','','cat'])
        except:
            raise
        else:
            vals = dmGetData(scol_dd, nrows=4)
            print(vals.astype(self._stype), file=self.fh)

        print("  dmSetData (scol_dd, [5,6])", file=self.fh)
        try:
            dmSetData (scol_dd, [5,6])
        except:
            raise
        else:
            vals = dmGetData(scol_dd, nrows=4)
            print(vals.astype(self._stype), file=self.fh)

        print("  dmSetData (scol_dd, ['bird',8])", file=self.fh)
        try:
            dmSetData (scol_dd, ['bird',8])
        except:
            raise
        else:
            vals = dmGetData(scol_dd, nrows=4)
            print(vals.astype(self._stype), file=self.fh)


        print("  dmGetSata (jcol_dd, [1,2.2,3])", file=self.fh)
        try:
            dmSetData (jcol_dd, [1,2.2,3])
        except:
            raise
        else:
            print(dmGetData (jcol_dd, nrows=4), file=self.fh)

        print("  dmSetData (lcol_dd, [True]*4)", file=self.fh)
        try:
            dmSetData (lcol_dd, [True]*4)
        except:
            raise
        else:
            print(dmGetData (lcol_dd, nrows=4), file=self.fh)

        print("  dmSetData (bcol_dd, [0b1000010,32,0xf])", file=self.fh)
        try:
            dmSetData (bcol_dd, [0b1000010,32,0xf])
        except:
            raise
        else:
            print(dmGetData (bcol_dd, nrows=4), file=self.fh)

        print("  dmSetData (dacol_dd, [[201,'9',5],[202,203,204.6]])", file=self.fh)
        try:
            dmSetData (dacol_dd, [[201,'9',5],[202,203,204.6]])
        except:
            raise
        else:
            print(dmGetData (dacol_dd, nrows=4), file=self.fh)

        print("  dmSetData (sky_dd, [[2,3],[4,5],[6,7],[8,9]])", file=self.fh)
        try:
            dmSetData (sky_dd, [[2,3],[4,5],[6,7],[8,9]])
        except:
            raise
        else:
            print(dmGetData (sky_dd, nrows=4), file=self.fh)

        #select row
        print("  dmSetData (scol_dd, ['dog','cat'],2)", file=self.fh)
        try:
            dmSetData (scol_dd, ['dog','cat'],2)
        except:
            raise
        else:
            vals = dmGetData(scol_dd, nrows=4)
            print(vals.astype(self._stype), file=self.fh)

        print("  data = dmGetData (jcol_dd, 3,2)\n  dmSetData (jcol_dd, data, 2)", file=self.fh)
        try:
            data = dmGetData (jcol_dd, 3,2)
            dmSetData (jcol_dd, data, 2)
        except:
            raise
        else:
            dmTableSetRow(t, 1)  
            print(dmGetData (jcol_dd, nrows=4), file=self.fh)

        print("  dmSetData (lcol_dd, [False,True],rowno=3)", file=self.fh)
        try:
            dmSetData (lcol_dd, [False,True],rowno=3)
        except:
            raise
        else:
            print(dmGetData (lcol_dd, nrows=4), file=self.fh)

        print("  data = dmGetData (dacol_dd, 3,2)\n  dmSetData (dacol_dd, data, 2)", file=self.fh)
        try:
            data = dmGetData (dacol_dd, 3, 2)
            dmSetData (dacol_dd, data, 2)
        except:
            raise
        else:
            dmTableSetRow(t, 1)  
            print(dmGetData (dacol_dd, nrows=4), file=self.fh)

        print("  dmSetData (sky_dd, [[1000,2000.1],[1000.1,2000.2]],3)", file=self.fh)
        try:
            dmSetData (sky_dd, [[1000,2000.1],[1000.1,2000.2]],3)
        except:
            raise
        else:
            dmTableSetRow(t, 1)  
            print(dmGetData (sky_dd, nrows=4), file=self.fh)

        
        print("  data = dmGetData (da_col_dd)", file=self.fh)
        print("  dmSetData (dacol_dd, data)", file=self.fh)
        data = dmGetData (dacol_dd, nrows=2)

        try:
            dmSetData (dacol_dd, [[201,'9',5],[202,203,204.6]])
        except:
            raise
        else:
            dmTableSetRow(t, 1)  
            print(dmGetData (dacol_dd, nrows=4), file=self.fh)

        # data from image -- behavior undefined. it may default to 
        # dmSetImageData or error out.

        # error checking
        print("  dmSetData (jcol_dd, [[1,2],[3,4]])", file=self.fh)
        try:
            dmSetData (jcol_dd, [[1,2],[3,4]])
        except Exception as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        else:
            raise RuntimeError ("     Unexpected Pass ... FAIL")


	# malformed array: numpy <  1.24 converts to np.object type which == 'unsupported type'
	# malformed array: numpy >= 1.24 creates exception
        # Duplicate test condition by simply sending in np.object instance.
        obj = np.object_

        print("  dmSetData (dacol_dd, [[1,2],[3,4,3]])", file=self.fh)
        try:
            dmSetData (dacol_dd, obj)
        except ValueError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        else:
            raise RuntimeError ("     Unexpected Pass ... FAIL")


        print("  dmSetData (dacol_dd, [[1,2,3,4,5,6],[3,4,3,4,5,6]])", file=self.fh)
        try:
            dmSetData (dacol_dd, [[1,2,3,4,5,6],[3,4,3,4,5,6]])
        except ValueError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        else:
            raise RuntimeError ("     Unexpected Pass ... FAIL")

        print("  dmSetData (dacol_dd, [[1,2],[3,4]], 20)", file=self.fh)
        try:
            dmSetData (dacol_dd, [[1,2],[3,4]], 20)
        except Exception as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        else:
            raise RuntimeError ("     Unexpected Pass ... FAIL")


        print("  dmSetData (dacol_dd, 1)", file=self.fh)
        try:
            dmSetData (dacol_dd, 1)
        except Exception as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        else:
            raise RuntimeError ("     Unexpected Pass ... FAIL")



        # open table with varlen scalar column
        v = dmTableOpen ( infile3 )

        nrows = 4

        var_dd = dmTableOpenColumn(v, "VSCAL1")

        print("  dmSetData (var_dd, <varlen scalar array>) - DOUBLE", file=self.fh)
        try:
            rowdata = np.empty(shape=(nrows), dtype=object)
            rowdata[0]  = np.array([1111111.346,1111112.835,1111113.23468,1111114.745], dtype=np.float64)
            rowdata[1]  = np.array([2222221.8460,2222222.0348], dtype=np.float64)
            rowdata[2]  = np.array([3333331.89046,3333332.98243,3333333.027549,3333334.97345,3333335.19387], dtype=np.float64)
            rowdata[3]  = np.array([4444441.8023], dtype=np.float64)

            for ii in range(1, nrows+1):
                dmSetData (var_dd, rowdata[ii-1], ii)
                dmTableNextRow( v )
            dmTableSetRow(v, 1)       
        except:
            raise
 
        else:
            print(dmGetData (var_dd, nrows=nrows), file=self.fh)


        var_dd = dmTableOpenColumn(v, "VSCAL2")

        print("  dmSetData (var_dd, <varlen scalar array>) - FLOAT", file=self.fh)
        try:
            rowdata = np.empty(shape=(nrows), dtype=object)
            rowdata[0]  = np.array([1111.346,1112.835,1113.23468,1114.745], dtype=np.float32)
            rowdata[1]  = np.array([2221.8460,2222.0348], dtype=np.float32)
            rowdata[2]  = np.array([3331.89046,3332.98243,3333.027549,3334.97345,3335.19387], dtype=np.float32)
            rowdata[3]  = np.array([4441.8023], dtype=np.float32)

            for ii in range(1, nrows+1):
                dmSetData (var_dd, rowdata[ii-1], ii)
                dmTableNextRow( v )
            dmTableSetRow(v, 1)       
        except:
            raise
 
        else:
            print(dmGetData (var_dd, nrows=nrows), file=self.fh)



        var_dd = dmTableOpenColumn(v, "VSCAL3")

        print("  dmSetData (var_dd, <varlen scalar array>) - LONG", file=self.fh)
        try:
            rowdata = np.empty(shape=(nrows), dtype=object)
            rowdata[0]  = np.array([122211,133312,144413,155514], dtype=np.int64)
            rowdata[1]  = np.array([2666621,2777722], dtype=np.int64)
            rowdata[2]  = np.array([34431,35532,36633,37734,335], dtype=np.int64)
            rowdata[3]  = np.array([4541], dtype=np.int64)

            for ii in range(1, nrows+1):
                dmSetData (var_dd, rowdata[ii-1], ii)
                dmTableNextRow( v )
            dmTableSetRow(v, 1)       
        except:
            raise
 
        else:
            print(dmGetData (var_dd, nrows=nrows), file=self.fh)


        var_dd = dmTableOpenColumn(v, "VSCAL4")

        print("  dmSetData (var_dd, <varlen scalar array>) - SHORT", file=self.fh)
        try:
            rowdata = np.empty(shape=(nrows), dtype=object)
            rowdata[0]  = np.array([1011,12,1013,14], dtype=np.short)
            rowdata[1]  = np.array([221,20222], dtype=np.short)
            rowdata[2]  = np.array([331,332,333,334,335], dtype=np.short)
            rowdata[3]  = np.array([4041], dtype=np.short)

            for ii in range(1, nrows+1):
                dmSetData (var_dd, rowdata[ii-1], ii)
                dmTableNextRow( v )
            dmTableSetRow(v, 1)       
        except:
            raise
 
        else:
            print(dmGetData (var_dd, nrows=nrows), file=self.fh)



        var_dd = dmTableOpenColumn(v, "VSCAL5")

        print("  dmSetData (var_dd, <varlen scalar array>) - BYTE", file=self.fh)
        try:
            rowdata = np.empty(shape=(nrows), dtype=object)
            rowdata[0]  = np.array([10, 20, 35, 44], dtype=np.short)
            rowdata[1]  = np.array([52, 67], dtype=np.short)
            rowdata[2]  = np.array([34, 0, 0, 130, 235], dtype=np.short)
            rowdata[3]  = np.array([3], dtype=np.short)

            for ii in range(1, nrows+1):
                dmSetData (var_dd, rowdata[ii-1], ii)
                dmTableNextRow( v )
            dmTableSetRow(v, 1)       
        except:
            raise
 
        else:
            print(dmGetData (var_dd, nrows=nrows), file=self.fh)


        var_dd = dmTableOpenColumn(v, "VSCAL6")

        print("  dmSetData (var_dd, <varlen scalar array>) - BOOLEAN", file=self.fh)
        try:
            rowdata = np.empty(shape=(nrows), dtype=object)
            rowdata[0]  = np.array([True,True,False,True], dtype=np.bool_)
            rowdata[1]  = np.array([False,False], dtype=np.bool_)
            rowdata[2]  = np.array([True,False,True,False,False], dtype=np.bool_)
            rowdata[3]  = np.array([True], dtype=np.bool_)

            for ii in range(1, nrows+1):
                dmSetData (var_dd, rowdata[ii-1], ii)
                dmTableNextRow( v )
            dmTableSetRow(v, 1)       
        except:
            raise
 
        else:
            print(dmGetData (var_dd, nrows=nrows), file=self.fh)


        # open table with varlen vector column
        vv = dmTableOpen ( infile4 )


        varvec_dd = dmTableOpenColumn(vv, "VVECT1")
 
        print("  dmSetData (varvec_dd, <varlen vector array> - DOUBLE)", file=self.fh)
        try:
            vrowdata = np.empty(shape=(nrows), dtype=object)
            vrowdata[0]  = np.array([[5551000.11,42000.11,3000.11,4000.11],[1011.11,2999011.11,3011.11,4999011.11]], dtype=np.float64)
            vrowdata[1]  = np.array([[5551000.22,62000.22],[122.22,222.22]], dtype=np.float64)
            vrowdata[2]  = np.array([[5551000.33],[71033.33]], dtype=np.float64)
            vrowdata[3]  = np.array([[5551000.44],[81044.44]], dtype=np.float64)

            for ii in range(1, nrows+1):
                dmSetData (varvec_dd, vrowdata[ii-1])
                dmTableNextRow( vv )
            dmTableSetRow(vv, 1)       
        except:
            raise
 
        else:
            print(dmGetData (varvec_dd, nrows=nrows), file=self.fh)


        varvec_dd = dmTableOpenColumn(vv, "VVECT2")
 
        print("  dmSetData (varvec_dd, <varlen vector array> - FLOAT)", file=self.fh)
        try:
            vrowdata = np.empty(shape=(nrows), dtype=object)
            vrowdata[0]  = np.array([[1000.11,2000.11,3000.11,4000.11],[1011.11,2011.11,3011.11,4011.11]], dtype=np.float32)
            vrowdata[1]  = np.array([[1000.22,2000.22],[1022.22,2022.22]], dtype=np.float32)
            vrowdata[2]  = np.array([[1000.33],[1033.33]], dtype=np.float32)
            vrowdata[3]  = np.array([[1000.44],[1044.44]], dtype=np.float32)

            for ii in range(1, nrows+1):
                dmSetData (varvec_dd, vrowdata[ii-1])
                dmTableNextRow( vv )
            dmTableSetRow(vv, 1)       
        except:
            raise
 
        else:
            print(dmGetData (varvec_dd, nrows=nrows), file=self.fh)



        varvec_dd = dmTableOpenColumn(vv, "VVECT3")
 
        print("  dmSetData (varvec_dd, <varlen vector array> - LONG)", file=self.fh)
        try:
            vrowdata = np.empty(shape=(nrows), dtype=object)
            vrowdata[0]  = np.array([[111,2211,33311,444411],[511,6666611,77711,888888811]], dtype=np.int32)
            vrowdata[1]  = np.array([[1222,22],[122,22222]], dtype=np.int32)
            vrowdata[2]  = np.array([[13],[10333333]], dtype=np.int32)
            vrowdata[3]  = np.array([[1444],[4]], dtype=np.int32)

            for ii in range(1, nrows+1):
                dmSetData (varvec_dd, vrowdata[ii-1])
                dmTableNextRow( vv )
            dmTableSetRow(vv, 1)       
        except:
            raise
 
        else:
            print(dmGetData (varvec_dd, nrows=nrows), file=self.fh)



        varvec_dd = dmTableOpenColumn(vv, "VVECT4")
 
        print("  dmSetData (varvec_dd, <varlen vector array> - SHORT)", file=self.fh)
        try:
            vrowdata = np.empty(shape=(nrows), dtype=object)
            vrowdata[0]  = np.array([[111,221,33,4],[51,6,177,8]], dtype=np.int16)
            vrowdata[1]  = np.array([[222,22],[12,2]], dtype=np.int16)
            vrowdata[2]  = np.array([[13],[33]], dtype=np.int16)
            vrowdata[3]  = np.array([[144],[4]], dtype=np.int16)

            for ii in range(1, nrows+1):
                dmSetData (varvec_dd, vrowdata[ii-1])
                dmTableNextRow( vv )
            dmTableSetRow(vv, 1)       
        except:
            raise
 
        else:
            print(dmGetData (varvec_dd, nrows=nrows), file=self.fh)


        varvec_dd = dmTableOpenColumn(vv, "VVECT5")
 
        print("  dmSetData (varvec_dd, <varlen vector array> - BYTE)", file=self.fh)
        try:
            vrowdata = np.empty(shape=(nrows), dtype=object)
            vrowdata[0]  = np.array([[11,21,31,41],[10,20,30,40]], dtype=np.uint8)
            vrowdata[1]  = np.array([[212,222],[223,224]], dtype=np.uint8)
            vrowdata[2]  = np.array([[13],[33]], dtype=np.uint8)
            vrowdata[3]  = np.array([[114],[144]], dtype=np.uint8)

            for ii in range(1, nrows+1):
                dmSetData (varvec_dd, vrowdata[ii-1])
                dmTableNextRow( vv )
            dmTableSetRow(vv, 1)       
        except:
            raise
 
        else:
            print(dmGetData (varvec_dd, nrows=nrows), file=self.fh)



        varvec_dd = dmTableOpenColumn(vv, "VVECT6")
 
        print("  dmSetData (varvec_dd, <varlen vector array>) - BOOLEAN", file=self.fh)
        try:
            vrowdata = np.empty(shape=(nrows), dtype=object)
            vrowdata[0]  = np.array([[False,True, False,True],[True, True, False, False]], dtype=np.bool_)
            vrowdata[1]  = np.array([[True,True],[False,False]], dtype=np.bool_)
            vrowdata[2]  = np.array([[False],[False]], dtype=np.bool_)
            vrowdata[3]  = np.array([[True],[False]], dtype=np.bool_)

            for ii in range(1, nrows+1):
                dmSetData (varvec_dd, vrowdata[ii-1])
                dmTableNextRow( vv )
            dmTableSetRow(vv, 1)       
        except:
            raise
 
        else:
            print(dmGetData (varvec_dd, nrows=nrows), file=self.fh)


    # ----------------------------------------------------------------------
    #
    # ----------------------------------------------------------------------
    def test_113( self ):
        """
        dmImageGetData

        """

        print("Running Unit Test 113", file=self.fh)

        # Assign input/output file names
        infile1 = self.indir + self.infiles[1] # image

        # open the Image
        i = dmImageOpen( infile1 )
        img_dd = dmImageGetDataDescriptor(i)

        print("  data = dmImageGetData (img_dd)", file=self.fh)
        try:
            data = dmImageGetData (img_dd)
        except:
            raise
        else:
            print(data, file=self.fh)

        print("  data = dmImageGetData (img_dd, 3)", file=self.fh)
        try:
            data = dmImageGetData (img_dd,3)
        except:
            raise
        else:
            print(data, file=self.fh)


        print("  data = dmImageGetData (img_dd, 3,4)", file=self.fh)
        try:
            data = dmImageGetData (img_dd,3,4)
        except:
            raise
        else:
            print(data, file=self.fh)

        print("  data = dmImageGetData (img_dd, [2,3])", file=self.fh)
        try:
            data = dmImageGetData (img_dd,[2,3])
        except:
            raise
        else:
            print(data, file=self.fh)

        print("  data = dmImageGetData (img_dd, [4,2],5)", file=self.fh)
        try:
            data = dmImageGetData (img_dd,[4,2],5)
        except:
            raise
        else:
            print(data, file=self.fh)

        print("  data = dmImageGetData (img_dd, pixelLL=[2,3],pixelUR=[3,3])", file=self.fh)
        try:
            data = dmImageGetData (img_dd,pixelLL=[2,3],pixelUR=[3,3])
        except:
            raise
        else:
            print(data, file=self.fh)

        print("  data = dmImageGetData (img_dd, pixelUR=[3,3])", file=self.fh)
        try:
            data = dmImageGetData (img_dd, pixelUR=[3,3])
        except:
            raise
        else:
            print(data, file=self.fh)

        print("  data = dmImageGetData (img_dd, pixelUR=[3,3])", file=self.fh)
        try:
            data = dmImageGetData (img_dd, pixelUR=1)
        except:
            raise
        else:
            print(data, file=self.fh)


        print("  data = dmImageGetData (img_dd, pixelUR=[3,3])", file=self.fh)
        try:
            data = dmImageGetData (img_dd, pixelUR=[1,1])
        except:
            raise
        else:
            print(data, file=self.fh)


        # error checking
        print("  dmImageGetData (img_dd, [1,2,3])", file=self.fh)
        try:
            dmImageGetData (img_dd, [1,2,3])
        except ValueError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        else:
            raise RuntimeError ("     Unexpected Pass ... FAIL")

        print("  dmImageGetData (img_dd, pixelUR=[1,2,3])", file=self.fh)
        try:
            dmImageGetData (img_dd, pixelUR=[1,2,3])
        except ValueError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        else:
            raise RuntimeError ("     Unexpected Pass ... FAIL")

        
        print("  dmImageGetData (img_dd, [1.1,2.2])", file=self.fh)
        try:
            dmImageGetData (img_dd, [1.1,2.2])
        except ValueError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        else:
            raise RuntimeError ("     Unexpected Pass ... FAIL")


    # ----------------------------------------------------------------------
    #
    # ----------------------------------------------------------------------
    def test_114( self ):
        """
        dmImageSetData

        """

        print("Running Unit Test 114", file=self.fh)

        # Assign input/output file names
        infile1 = self.indir + self.infiles[1] # image

        # open the Image
        i = dmImageOpen( infile1 )
        img_dd = dmImageGetDataDescriptor(i)

        print("  dmImageSetData (img_dd,101)", file=self.fh)
        try:
            dmImageSetData (img_dd, 101)
        except:
            raise
        else:
            print(dmImageGetData (img_dd), file=self.fh)

        print("  dmImageSetData (img_dd,[201,202,203])", file=self.fh)
        try:
            dmImageSetData (img_dd, [201,202,203])
        except:
            raise
        else:
            print(dmImageGetData (img_dd), file=self.fh)

        print("  dmImageSetData (img_dd,[[301,302,303],[311,312,313]],[321,322,323]])", file=self.fh)
        try:
            dmImageSetData (img_dd,[[301,302,303],[311,312,313],[321,322,323]])
        except:
            raise
        else:
            print(dmImageGetData (img_dd), file=self.fh)


        print("  dmImageSetData (img_dd,401,3)", file=self.fh)
        try:
            dmImageSetData (img_dd,401,3)
        except:
            raise
        else:
            print(dmImageGetData (img_dd), file=self.fh)


        print("  dmImageSetData (img_dd,411,[3,2])", file=self.fh)
        try:
            dmImageSetData (img_dd,411,[3,2])
        except:
            raise
        else:
            print(dmImageGetData (img_dd), file=self.fh)


        print("  dmImageSetData (img_dd,[511,512],[4,2])", file=self.fh)
        try:
            dmImageSetData (img_dd,[512,513],[4,2])
        except:
            raise
        else:
            print(dmImageGetData (img_dd), file=self.fh)


        print("  dmImageSetData (img_dd,[[601,602],[611,612],[621,622]],pixelLL=[4,1])", file=self.fh)
        try:
            dmImageSetData (img_dd,[[601,602],[611,612],[621,622]],pixelLL=[4,1])
        except:
            raise
        else:
            print(dmImageGetData (img_dd), file=self.fh)


        # error checking
        print("  dmImageSetData (img_dd, [[[1],[2]]])", file=self.fh)
        try:
            dmImageSetData (img_dd, [[[1],[2]]])
        except ValueError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        else:
            raise RuntimeError ("     Unexpected Pass ... FAIL")


        print("  dmImageSetData (img_dd, [1,2,3], [1,2,3])", file=self.fh)
        try:
            dmImageSetData (img_dd, [1,2,3], [1,2,3])
        except ValueError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        else:
            raise RuntimeError ("     Unexpected Pass ... FAIL")


    # ----------------------------------------------------------------------
    #
    # ----------------------------------------------------------------------
    def test_115( self ):
        """
        dmBlockSetSubspaceCpt
        dmSubspaceColGet

        """

        print("Running Unit Test 115", file=self.fh)

        # Assign input/output file names
        infile = self.indir + self.infiles[2] # multi component table

        # open the Table
        t = dmTableOpen ( infile )


        subspace_dd = dmSubspaceColOpen (t,"expno")
        print("  data = dmSubspaceColGet (subspace_dd)  #expno", file=self.fh)
        try:
            data = dmSubspaceColGet (subspace_dd)
        except:
            raise
        else:
            print(data, file=self.fh)

        subspace_dd = dmSubspaceColOpen (t,"time")
        print("  data = dmSubspaceColGet (subspace_dd)  #time", file=self.fh)
        try:
            data = dmSubspaceColGet (subspace_dd)
        except:
            raise
        else:
            print(data, file=self.fh)

        subspace_dd = dmSubspaceColOpen (t,"sky")
        print("  data = dmSubspaceColGet (subspace_dd)  #sky", file=self.fh)
        try:
            data = dmSubspaceColGet (subspace_dd)
        except:
            raise
        else:
            print(data, file=self.fh)

        vdd = subspace_dd
        
        print("  data = dmSubspaceColGet (subspace_dd)  #x - cpt of sky", file=self.fh)
        subspace_dd = dmGetCpt( vdd, 1 )
        try:
            data = dmSubspaceColGet (subspace_dd)
        except:
            raise
        else:
            print(data, file=self.fh)
        
        print("  data = dmSubspaceColGet (subspace_dd)  #y - cpt of sky", file=self.fh)
        subspace_dd = dmGetCpt( vdd, 2 )
        try:
            data = dmSubspaceColGet (subspace_dd)
        except:
            raise
        else:
            print(data, file=self.fh)

        subspace_dd = dmSubspaceColOpen (t,"ccd_id")
        print("  data = dmSubspaceColGet (subspace_dd)  #ccd_id", file=self.fh)
        try:
            data = dmSubspaceColGet (subspace_dd)
        except:
            raise
        else:
            print(data, file=self.fh)

        print("  dmBlockSetSubspaceCpt (t,1); data = dmSubspaceColGet (subspace_dd)  #ccd_id", file=self.fh)
        try:
            dmBlockSetSubspaceCpt (t,2)
            data = dmSubspaceColGet (subspace_dd)
        except:
            raise
        else:
            print(data, file=self.fh)

        


    # ----------------------------------------------------------------------
    #
    # ----------------------------------------------------------------------
    def test_116( self ):
        """
        dmCoordCalc
        dmCoordInvert
        dmCoordGetTransform
        dmCoordSetParam

        """

        print("Running Unit Test 116", file=self.fh)

        # Assign input/output file names
        infile1 = self.indir + self.infiles[1] # image
        infile2 = self.indir + self.infiles[0] # table

        # open the Table
        t = dmTableOpen ( infile2 )
        eqpos_dd = dmTableOpenColumn (t, "eqpos")
        sky_dd = dmTableOpenColumn (t, "sky")
        icol_dd = dmTableOpenColumn (t, "icol")

        # open the image
        i = dmImageOpen( infile1 )
        img_dd = dmImageGetDataDescriptor(i)

        print("  transform = dmCoordGetTransform (eqpos_dd)", file=self.fh)
        try:
            transform = dmCoordGetTransform (eqpos_dd)
        except:
            raise
        else:
            print(transform, file=self.fh)


        print("  world_coord = dmCoordCalc (eqpos_dd,[100,100])", file=self.fh)
        try:
            world_coord = dmCoordCalc (eqpos_dd, [100,100])
        except:
            raise
        else:
            print(world_coord, file=self.fh)

        print("  sky_coord = dmCoordInvert (eqpos_dd,{0})".format (world_coord), file=self.fh)
        try:
            sky_coord = dmCoordInvert (eqpos_dd, world_coord)
        except:
            raise
        else:
            print(sky_coord, file=self.fh) 

        print("  world_coord = dmCoordCalc (eqpos_dd,[[100,100],[200,200],[300,300]])", file=self.fh)
        try:
            world_coord = dmCoordCalc (eqpos_dd, [[100,100],[200,200],[300,300]])
        except:
            raise
        else:
            print(world_coord, file=self.fh)

        print("  sky_coord = dmCoordInvert (eqpos_dd,{0})".format (world_coord), file=self.fh)
        try:
            sky_coord = dmCoordInvert (eqpos_dd, world_coord)
        except:
            raise
        else:
            print(sky_coord, file=self.fh) 


        print("  transform = dmCoordGetTransform (sky_dd)", file=self.fh)
        try:
            transform = dmCoordGetTransform (sky_dd)
        except:
            raise
        else:
            print(transform, file=self.fh)

        print("  sky_coord = dmCoordCalc (sky_dd,[500.25,250])", file=self.fh)
        try:
            sky_coord = dmCoordCalc (sky_dd, [500.25,250])
        except:
            raise
        else:
            print(sky_coord, file=self.fh)

        print("  sky_coord = dmCoordInvert (sky_dd,{0})".format (sky_coord), file=self.fh)
        try:
            sky_coord = dmCoordInvert (sky_dd, sky_coord)
        except:
            raise
        else:
            print(sky_coord, file=self.fh)


        print("  transform = dmCoordGetTransform (icol_dd)", file=self.fh)
        try:
            transform = dmCoordGetTransform (icol_dd)
        except:
            raise
        else:
            print(transform, file=self.fh)

        print("  icol_coord = dmCoordCalc (icol_dd,10)", file=self.fh)
        try:
            icol_coord = dmCoordCalc (icol_dd, 10)
        except:
            raise
        else:
            print(icol_coord, file=self.fh)

        print("  icol_coord = dmCoordInvert (icol_dd,{0})".format (icol_coord), file=self.fh)
        try:
            icol_coord = dmCoordInvert (icol_dd,icol_coord)
        except:
            raise
        else:
            print(icol_coord, file=self.fh)


        print("  transform = dmCoordGetTransform (img_dd)", file=self.fh)
        try:
            transform = dmCoordGetTransform (img_dd)
        except:
            raise
        else:
            print(transform, file=self.fh)


        axis_dd = dmArrayGetAxisGroup (img_dd, 1)
        print("  transform = dmCoordGetTransform (axis_dd)", file=self.fh)
        try:
            transform = dmCoordGetTransform (axis_dd)
        except:
            raise
        else:
            print(transform, file=self.fh)

        print("  img_coord = dmCoordCalc (axis_dd,[10,10])", file=self.fh)
        try:
            img_coord = dmCoordCalc (axis_dd,[10,10])
        except:
            raise
        else:
            print(img_coord, file=self.fh)

        print("  img_coord = dmCoordInvert (axis_dd,{0})".format (img_coord), file=self.fh)
        try:
            img_coord = dmCoordInvert (axis_dd,img_coord)
        except:
            raise
        else:
            print(img_coord, file=self.fh)




        # error checking
        print("  dmCoordGetTransform ()", file=self.fh)
        try:
            dmCoordGetTransform ()
        except TypeError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        else:
            raise RuntimeError ("     Unexpected Pass ... FAIL")

        print("  dmCoordCalc ()", file=self.fh)
        try:
            dmCoordCalc ()
        except TypeError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        else:
            raise RuntimeError ("     Unexpected Pass ... FAIL")


        print("  dmCoordCalc (eqpos_dd)", file=self.fh)
        try:
            dmCoordCalc (eqpos_dd)
        except TypeError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        else:
            raise RuntimeError ("     Unexpected Pass ... FAIL")

        print("  dmCoordInvert ()", file=self.fh)
        try:
            dmCoordInvert ()
        except TypeError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        else:
            raise RuntimeError ("     Unexpected Pass ... FAIL")


        print("  dmCoordInvert (eqpos_dd)", file=self.fh)
        try:
            dmCoordInvert (eqpos_dd)
        except TypeError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        else:
            raise RuntimeError ("     Unexpected Pass ... FAIL")


        # dmCoordSetParam:
        print("###  dmCoordSetParam ### ", file=self.fh)
        print("  dmCoordSetParam( t, 'blah', 2010.0 )  # bad check", file=self.fh)
        try:
            dmCoordSetParam( t, 'blah', 2010.0 )
        except TypeError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        else:
            raise RuntimeError ("     Unexpected Pass ... FAIL")


        print("  dmCoordSetParam( sky_dd, 'blah', 2010.0 )  # bad check - not coord", file=self.fh)
        try:
            dmCoordSetParam( sky_dd, 'blah', 2010.0 )
        except ValueError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        else:
            raise RuntimeError ("     Unexpected Pass ... FAIL")


        # NOTE: parameter name set is not enforced by DM library..
        print("  dmCoordSetParam( eqpos_dd, 'blah', 2010.0 )  # bad check - not invalid param name", file=self.fh)
        try:
            dmCoordSetParam( eqpos_dd, 'blah', 2010.0 )
        except ValueError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        else:
            print("     Desired error not enforced.  Expected ... OK", file=self.fh)

        print("  dmCoordSetParam( eqpos_dd, 'EQUINOX', 2010.0 )  # good", file=self.fh)
        try:
            dmCoordSetParam( eqpos_dd, 'EQUINOX', 2010.0 )
        except:
            raise


        print("  dmCoordSetParam( eqpos_dd, 'LATPOLE', 122 )  # good", file=self.fh)
        try:
            dmCoordSetParam( eqpos_dd, 'LATPOLE', 122 )
        except:
            raise


        arval = np.array([5.0,3.0], dtype=np.double);
        print("  dmCoordSetParam( eqpos_dd, 'ROT', arval )  # bad - non-scalar value", file=self.fh)
        try:
            dmCoordSetParam( eqpos_dd, 'ROT', [2010.0,33.5] )
        except TypeError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        else:
            raise RuntimeError ("     Unexpected Pass ... FAIL")


        dmTableClose(t)



    # ----------------------------------------------------------------------
    #
    # ----------------------------------------------------------------------
    def test_117( self ):
        """
        dmTableAllocRow
        dmTableGetRows
        dmTableGetRow
        """
        print("Running Unit Test 117", file=self.fh)

        # Assign input/output file names
        infile = self.indir + self.infiles[0] # table

        # open the Table
        t = dmTableOpen ( infile )
        
        print("", file=self.fh)
        print("rdat = dmTableAllocRow(7)      # Expect to fail (bad input type)", file=self.fh)
        b = 7
        try:
            rdat = dmTableAllocRow(b)
        except TypeError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        else:
            raise RuntimeError ("Expected failure did not occur!")


        print("", file=self.fh)
        print("rdat = dmTableAllocRow(b)      # Expect to fail (empty block)", file=self.fh)
        b = dmBlock()
        try:
            rdat = dmTableAllocRow(b)
        except TypeError as e:
            print("    ", e, file=self.fh)
            raise
        except Exception as g:
            print("    ", g, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        else:
            raise RuntimeError ("Expected failure did not occur!")

        print("", file=self.fh)
        print("rdat = dmTableAllocRow(t)      # Good.. allocate 1 row using dmBlock", file=self.fh)
        try:
            rdat = dmTableAllocRow(t)
        except Exception as e:
            print("    ", e, file=self.fh)
            raise
        else:
            print("Successfully allocated row", file=self.fh)
            print(rdat.dtype, file=self.fh)
            print(rdat, file=self.fh)

        print("", file=self.fh)
        print("dat = dmTableGetRows(t, -10)    # Bad.. Nrows < 1.", file=self.fh)
        try:
            dat = dmTableGetRows(t, -10)
        except ValueError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        else:
            raise RuntimeError ("Expected failure did not occur!")

        print("", file=self.fh)
        print("dat = dmTableGetRows(t, 3)    # Good.. Read 3 of 4 rows", file=self.fh)
        try:
            dat = dmTableGetRows(t, 3)
        except Exception as e:
            print("    ", e, file=self.fh)
            raise
        else:
            print("Successfully read %d rows" % len(dat), file=self.fh)
            print(dat.dtype, file=self.fh)
            print(dat, file=self.fh)

        print("", file=self.fh)
        print("dat = dmTableGetRows(t, 10)    # Good.. Read last row", file=self.fh)
        try:
            dat = dmTableGetRows(t, 10)
        except Exception as e:
            print("    ", e, file=self.fh)
            raise
        else:
            print("Successfully read %d rows" % len(dat), file=self.fh)
            print(dat.dtype, file=self.fh)
            print(dat, file=self.fh)
            
        print("", file=self.fh)
        print("dat = dmTableGetRows(t, 5)    # Good.. Read more rows.. but already at EOF", file=self.fh)
        try:
            dat = dmTableGetRows(t, 5)
        except Exception as e:
            print("    ", e, file=self.fh)
            raise
        else:
            if dat is None:
                print("No rows read", file=self.fh)
            else:
                print("Successfully read rows", file=self.fh)
                print(dat.dtype, file=self.fh)
                print(dat, file=self.fh)
                raise RuntimeError ("Expected result did not occur!")

        dmTableClose(t)

        print("", file=self.fh)
        print("", file=self.fh)
        print("Read each row in loop", file=self.fh)
        t = dmTableOpen ( infile )
        done = False
        while not done:
            rdat = dmTableGetRow( t )
            if rdat is None:
                done = True
            else:
                print("  dat = dmTableGetRow(t)       # Good.. ", file=self.fh)
                print(rdat, file=self.fh)
    
        dmTableClose(t)



    # ----------------------------------------------------------------------
    #
    # ----------------------------------------------------------------------
    def test_118( self ):
        """
        CXCDM Memory Management
        """
        print("Running Unit Test 118", file=self.fh)

        # Assign input/output file names
        tabfile = self.indir + self.infiles[0] # table
        imgfile = self.indir + self.infiles[1] # image
        outfile = self.outdir + self.outfiles[20] # capture subtest python verbose output
                                                  # splits Python and C streams which do not
                                                  # always sync.  C-level verbose captured here.
        appdir  = os.path.dirname( os.path.realpath( __file__ ) )
        
        cmd = ["python", appdir + "/test_mm.py", tabfile, imgfile, outfile]

        h = subprocess.Popen( cmd, bufsize=0, universal_newlines=True, stdout=subprocess.PIPE )
        subout = h.communicate()
        for line in subout:
            print(line, file=self.fh)

    # ----------------------------------------------------------------------
    # dmDatasetDestroy
    # ----------------------------------------------------------------------
    def test_119( self ):
        """
        dmDatasetCreate
        dmDatasetDestroy
        """

        print("Running Test 119", file=self.fh)

        # create an output file that will be destroyed
        if sys.version_info[0] < 3:
            outfile = bytes(self.outdir + "testm000000000_DESTROY.fits")
            outfile2 =  bytes(self.outdir + "testm000000000_DELETE.fits")
        else:
            outfile = bytes(self.outdir + "testm000000000_DESTROY.fits", "utf-8")
            outfile2 =  bytes(self.outdir + "testm000000000_DELETE.fits", "utf-8")


        destds = dmDatasetCreate( outfile )
        ds2 = dmDatasetCreate( outfile2 )

        # verify the file was created
        if not os.path.isfile (outfile):
           raise RuntimeError ("Test file, %s, did not open with dmDatasetCreate"%outfile)
        else:
           print("Test file created %s"%(outfile.decode("utf-8")), file=self.fh)

        # destroy the file
        try:
            dmDatasetDestroy( outfile )
        except Exception as e:
            print("    ", e, file=self.fh)
            raise
        else:
           if os.path.isfile (outfile):
              raise RuntimeError ("Test file, %s, did not get destroyed with dmDatasetDestroy"%outfile)
           else:
              print("Test file destroyed %s"%(outfile.decode("utf-8")), file=self.fh)

        # create a non-writable file
        destds = dmDatasetCreate( outfile )
        os.chmod (outfile, 0)
        print("Test file %s chmod to 0"%(outfile.decode("utf-8")), file=self.fh)
        
        # try to destroy a read only file
        print("try to destroy a read only file", file=self.fh)
        try:
           dmDatasetDestroy( outfile )
        except IOError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        else:
            raise RuntimeError ("     Unexpected Pass ... FAIL")


        os.chmod (outfile, 0o755)
        print("Test file %s chmod to 744"%(outfile.decode("utf-8")), file=self.fh)

        # try to destroy a read only file
        print("destroy file", file=self.fh)
        dmDatasetDestroy( outfile )
        if os.path.isfile (outfile):
           raise RuntimeError ("Test file, %s, did not get destrpyed with dmDatasetDestroy"%outfile)
        else:
           print("Test file destroyed %s"%(outfile.decode("utf-8")), file=self.fh)

        # DatasetDelete tests 
        # verify the file was created
        if not os.path.isfile (outfile2):
           raise RuntimeError ("Test file, %s, did not open with dmDatasetCreate"%outfile2)
        else:
           print("Test file created %s"%(outfile2.decode("utf-8")), file=self.fh)
        # delete the file
        try:
          dmDatasetDelete( ds2 )
        except Exception as e:
           print("    ", e, file=self.fh)
           raise
        else:
           if os.path.isfile (outfile2):
              raise RuntimeError ("Test file, %s, did not get deleted with dmDatasetDelete"%outfile2)
           else:
              print("Test file deleted %s"%(outfile2.decode("utf-8")), file=self.fh)
        print("Call dmDatasetDelete again on same descriptor.", file=self.fh)
        try:
          dmDatasetDelete( ds2 )
        except Exception as e:
           print("    ", e, file=self.fh)
           print("     Expected ... OK", file=self.fh)
           pass

        # call dmDatasetDelete on different file
        deloutfile = self.outdir + "testm000000000_DELETE2.fits"
        delds2 = dmDatasetCreate( deloutfile )
        dmDatasetDelete( delds2 )


    # ----------------------------------------------------------------------
    # dmArrayCreateAxisGroup
    # ----------------------------------------------------------------------
    def test_120( self ):
        """
        dmArrayCreateAxisGroup
        """

        def verify_axisgroup_descriptor (coord_dd, img_dd, fh):
            'verify parameters of the axis group descriptor'

            if type(coord_dd) is dmDescriptor:
                print("     'coord_dd' verified as dmDescriptor type.", file=fh)
            else:
                print("     'coord_dd' is NOT a dmDescriptor type.", file=fh)
                raise Exception()

            print("     dmGetName (coord_dd) --> %s"%dmGetName (coord_dd), file=fh)
            print("     dmGetUnit (coord_dd) --> %s"%dmGetUnit (coord_dd), file=fh)

            dim = dmGetElementDim (coord_dd)
            for ii in range (1,dim+1):
               print("     dmGetCptName (coord_dd,%d) --> %s"%(ii,dmGetCptName(coord_dd, ii)), file=fh)
            num_axis_groups = dmArrayGetNoAxisGroups (img_dd)
            for ii in range (1, num_axis_groups+1):
               print("     axisgrp_dd = dmArrayGetAxisGroup (img_dd, %d)"%ii, file=fh)
               axisgrp_dd = dmArrayGetAxisGroup (img_dd, ii)
               print("     dmGetName (axisgrp_dd) --> %s"%dmGetName (axisgrp_dd), file=fh)


        print("Running Test 120", file=self.fh)

        infile1 = self.indir + self.infiles[1] # image

        # open image
        img = dmImageOpen( infile1 )
        img_dd = dmImageGetDataDescriptor(img)

        # check a list of components
        print("     coord_dd = dmArrayCreateAxisGroup (img_dd, 'TEST1', np.float, 'UNIT1', ['x','y'])", file=self.fh)
        try:
            coord_dd = dmArrayCreateAxisGroup (img_dd, 'TEST1', np.float64, 'UNIT1', ['x','y'])
        except:
            raise
        else:
            verify_axisgroup_descriptor (coord_dd, img_dd, self.fh)
        print("", file=self.fh)

        # check a single component
        print("     coord_dd = dmArrayCreateAxisGroup (img_dd, 'TEST2', np.float, 'UNIT2', 'z')", file=self.fh)
        try:
            coord_dd = dmArrayCreateAxisGroup (img_dd, 'TEST2', np.float64, 'UNIT2', 'z')
        except:
            raise
        else:
            verify_axisgroup_descriptor (coord_dd, img_dd, self.fh)
        print("", file=self.fh)

        # check empty descriptor
        dmImageClose (img)
        print("     dmImageClose (img)", file=self.fh)
        print("     dmArrayCreateAxisGroup ( img_dd, 'TEST3', np.float, 'UNIT3', 'a' )", file=self.fh)
        try:
           dmArrayCreateAxisGroup ( img_dd, 'TEST3', np.float64, 'UNIT3', 'a' )
        except ValueError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        else:
            raise RuntimeError ("     Unexpected Pass ... FAIL")

        img = dmImageOpen( infile1 )
        img_dd = dmImageGetDataDescriptor(img)
        # check empty cptnames
        print("     dmArrayCreateAxisGroup ( img_dd, 'TEST3', np.float, 'UNIT3', None )", file=self.fh)
        try:
           dmArrayCreateAxisGroup ( img_dd, 'TEST3', np.float64, 'UNIT3', None )
        except ValueError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        else:
            raise RuntimeError ("     Unexpected Pass ... FAIL")

        # check invalid cptnames
        print("     dmArrayCreateAxisGroup ( img_dd, 'TEST3', np.float, 'UNIT3', [1,2,3] )", file=self.fh)
        try:
           dmArrayCreateAxisGroup ( img_dd, 'TEST3', np.float64, 'UNIT3', [1,2,3] )
        except ValueError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        else:
            raise RuntimeError ("     Unexpected Pass ... FAIL")


        # check invalid datatype
        print("     dmArrayCreateAxisGroup ( img_dd, 'TEST3', [], 'UNIT3', 'a' )", file=self.fh)
        try:
           dmArrayCreateAxisGroup ( img_dd, 'TEST3', [], 'UNIT3', 'a' )
        except ValueError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        else:
            raise RuntimeError ("     Unexpected Pass ... FAIL")

    # ----------------------------------------------------------------------
    # dmDescriptorGetType
    # ----------------------------------------------------------------------
    def test_121( self ):
        """
        dmDescriptorGetType
        dmGetElementType
        """

        print("Running Test 121", file=self.fh)

        # Assign input/output file names
        infile1 = self.indir + self.infiles[1] # image
        infile2 = self.indir + self.infiles[0] # table

        # open the Table
        t = dmTableOpen ( infile2 )
        eqpos_dd = dmTableOpenColumn (t, "eqpos")
        icol_dd = dmTableOpenColumn (t, "icol")
        sc_dd = dmSubspaceColOpen(t, "sky")
        (key_dd,v) = dmKeyRead(t, "HISTNUM")

        # open the image
        img = dmImageOpen( infile1 )
        img_dd = dmImageGetDataDescriptor(img)

        print("     dmDescriptorGetType (icol_dd) --> {0}".format(dmDescriptorGetType (icol_dd)), file=self.fh)
        print("     dmDescriptorGetType (img_dd) --> {0}".format(dmDescriptorGetType (img_dd)), file=self.fh)
        print("     dmDescriptorGetType (eqpos_dd) --> {0}".format(dmDescriptorGetType (eqpos_dd)), file=self.fh)
        print("     dmDescriptorGetType (sc_dd) --> {0}".format(dmDescriptorGetType (sc_dd)), file=self.fh)
        print("     dmDescriptorGetType (key_dd) --> {0}".format(dmDescriptorGetType (key_dd)), file=self.fh)

        print("     dmGetElementType (icol) --> {0}".format(dmGetElementType (icol_dd)), file=self.fh)
        print("     dmGetElementType (sc_dd) --> {0}".format(dmGetElementType (sc_dd)), file=self.fh)
        print("     dmBADDESC, dmKEY, dmSUBSPACE, dmCOORD, dmCOLUMN --> {0}, {1}, {2}, {3}, {4}".format(dmBADDESC, dmKEY, dmSUBSPACE, dmCOORD, dmCOLUMN), file=self.fh)
        print("     dmVALUE, dmINTERVAL, dmRANGE --> {0}, {1}, {2}".format(dmVALUE, dmINTERVAL, dmRANGE), file=self.fh)



        print("     dmDescriptorGetType (img)", file=self.fh)
        try:
           dmDescriptorGetType (img)
        except TypeError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        else:
            raise RuntimeError ("     Unexpected Pass ... FAIL")

        dmImageClose (img)
        print("     dmImageClose (img)", file=self.fh)
        print("     dmDescriptorGetType (img_dd)", file=self.fh)
        try:
           dmDescriptorGetType (img_dd)
        except ValueError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        else:
            raise RuntimeError ("     Unexpected Pass ... FAIL")


    # ----------------------------------------------------------------------
    # dmDatasetGetBlock
    # ----------------------------------------------------------------------
    def test_122( self ):
        """
        dmDatasetGetBlock
        """

        print("Running Test 122", file=self.fh)

        # Assign input/output file names
        infile = self.indir + self.infiles[2] # table

        # open the dataset
        t = dmTableOpen ( infile )
        ds = dmBlockGetDataset (t)

        print("     b1 = dmDatasetGetBlock (ds, 2) -- get open block", file=self.fh)
        b1 = dmDatasetGetBlock (ds, 2)
        print("     dmBlockGetNo (b1) --> {0}".format (dmBlockGetNo (b1)), file=self.fh)

        print("     b2 = dmDatasetGetBlock (ds, 4) -- get closed block", file=self.fh)
        b2 = dmDatasetGetBlock (ds, 4)
        print("     dmBlockGetN0 (b2) --> {0}".format (dmBlockGetNo (b2)), file=self.fh)
        
        
        print("     b3 = dmDatasetGetBlock (ds, 'GTI6') -- get open block", file=self.fh)
        b3 = dmDatasetGetBlock (ds, 'GTI6')
        print("     dmBlockGetName (b3) --> {0}".format (dmBlockGetName (b3)), file=self.fh)

        print("     b4 = dmDatasetGetBlock (ds, 'GTI9') -- get closed block", file=self.fh)
        b4 = dmDatasetGetBlock (ds, 'GTI9')
        print("     dmBlockGetName (b4) --> {0}".format (dmBlockGetName (b4)), file=self.fh)

        try:
           dmDatasetGetBlock (ds, 'FOO')
        except ValueError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        else:
            raise RuntimeError ("     Unexpected Pass ... FAIL")


    # ----------------------------------------------------------------------
    # dmCoordCreate
    # ----------------------------------------------------------------------
    def test_123( self ):
        """
        dmCoordCreate
        """

        def verify_transform (output, dd):
     
           print("         "+dmGetName (dd), file=output)
           print("         "+dmGetUnit (dd), file=output)
           print("         "+str(dmCoordGetTransform (dd)), file=output)

        print("Running Test 123", file=self.fh)

        # Assign input/output file names
        outfile  = self.outdir + self.outfiles[9]

        # open a table and an image
        ds = dmDatasetCreate( outfile )
        tab = dmDatasetCreateTable( ds, "TABLE" )
        img = dmDatasetCreateImage ( ds, "IMAGE", np.int32, np.array([5,3], dtype=np.short))
        cols = dmColumnCreate( tab, [b"DCOL1", b"IVEC"], [np.float64, np.short], cptnames=[b"", [b"IV1",b"IV2"]] )
        img_dd = dmImageGetDataDescriptor(img)

        # create a 1D coords
        print('     coord_dd = dmCoordCreate (cols[0], "coord1", "foo")', file=self.fh)
        coord_dd = dmCoordCreate (cols[0], "coord1", "foo")
        verify_transform (self.fh, coord_dd)

        print('     coord_dd = dmCoordCreate (cols[0], "coord2", "foo", crpix=1, cdelt=2, crval=3)', file=self.fh)
        coord_dd = dmCoordCreate (cols[0], "coord2", "foo", crpix=1, cdelt=2, crval=3)
        verify_transform (self.fh, coord_dd)
        
        # create a 2D coord
        print('     coord_dd = dmCoordCreate (cols[1], "wcs_coord", "", cptnames=["IV1", "IV2"], transform="TAN", crpix=[1,1], cdelt=[.1, .1], crval=[10,10], params=[1,2,3,4])', file=self.fh)          
        coord_dd = dmCoordCreate (cols[1], "wcs_coord", "", cptnames=["IV1", "IV2"], transform="TAN", crpix=[1,1], cdelt=[.1, .1], crval=[10,10], params=[1,2,3,4])
        verify_transform (self.fh, coord_dd)


        # create a 2D linear coord 
        print('     coord_dd = dmCoordCreate (cols[1], "linear_coord_2d", "", cptnames=["IV1", "IV2"], crpix=[1,1], cdelt=[.1, .1], crval=[10,10], params=[1,2,3,4])', file=self.fh)
        coord_dd = dmCoordCreate (cols[1], "linear_coord_2d", "", cptnames=["IV1", "IV2"], crpix=[1,1], cdelt=[.1, .1], crval=[10,10], params=[1,2,3,4])
        verify_transform (self.fh, coord_dd)

        # create img coords
        print('     coord_dd = dmCoordCreate (axis_dd, "coord1", "foo", transform="SIN", crpix=[1,1], cdelt=[.1, .1], crval=[10,10], cptnames=(dmGetCptName (axis_dd,1), dmGetCptName (axis_dd,2)))', file=self.fh)
        axis_dd = dmArrayCreateAxisGroup (img_dd, b'TEST1', np.float64, b'UNIT1', [b'x',b'y'])
        coord_dd = dmCoordCreate (axis_dd, b"coord1", b"foo", transform=b"SIN", crpix=[1,1], cdelt=[.1, .1], crval=[10,10], cptnames=(dmGetCptName (axis_dd,1), dmGetCptName (axis_dd,2)))
        verify_transform (self.fh, coord_dd)


        # error check
        try:
           print('     coord_dd = dmCoordCreate (cols[1], "coord1", "foo", cptnames=["IV1", "IV2"])', file=self.fh)
           coord_dd = dmCoordCreate (cols[1], "coord1", "foo", cptnames=["IV1", "IV2"])
        except ValueError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        else:
            raise RuntimeError ("     Unexpected Pass ... FAIL")

        try:
           print('     coord_dd = dmCoordCreate (cols[0], "coord1", "foo", crpix=[1,2])', file=self.fh)
           coord_dd = dmCoordCreate (cols[0], "coord1", "foo", crpix=[1,2])
        except ValueError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        else:
            raise RuntimeError ("     Unexpected Pass ... FAIL")

        try:
           print('     coord_dd = dmCoordCreate (cols[0], "coord1", "foo", crpix=[1,2], cdelt=10, crval=[1,2])', file=self.fh)
           coord_dd = dmCoordCreate (cols[0], "coord1", "foo", crpix=[1,2], cdelt=10, crval=[1,2])
        except ValueError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        else:
            raise RuntimeError ("     Unexpected Pass ... FAIL")

        try:
           print('     coord_dd = dmCoordCreate (cols[0], "coord1", "foo", crpix=1, cdelt=10, crval=[[1,2],[1,2]])', file=self.fh)
           coord_dd = dmCoordCreate (cols[0], "coord1", "foo", crpix=1, cdelt=10, crval=[[1,2],[1,2]])
        except ValueError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        else:
            raise RuntimeError ("     Unexpected Pass ... FAIL")

        try:
           print('     coord_dd = dmCoordCreate (axis_dd, "coord1", "foo", transform="SIN", crpix=[1,1], cdelt=[.1, .1], crval=[10,10])', file=self.fh)
           axis_dd = dmArrayCreateAxisGroup (img_dd, 'TEST1', np.float64, 'UNIT1', ['x','y'])
           coord_dd = dmCoordCreate (axis_dd, "coord1", "foo", transform="SIN", crpix=[1,1], cdelt=[.1, .1], crval=[10,10])
        except ValueError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        else:
            raise RuntimeError ("     Unexpected Pass ... FAIL")

        try:
           #14293 - validate params argument: params[] != 4 elements
           print('     coord_dd = dmCoordCreate (cols[1], "wcs_coord", "", cptnames=["IV1", "IV2"], transform="TAN", crpix=[1,1], cdelt=[.1, .1], crval=[10,10], params=[1])', file=self.fh)
           coord_dd = dmCoordCreate (cols[1], "wcs_coord", "", cptnames=["IV1", "IV2"], transform="TAN", crpix=[1,1], cdelt=[.1, .1], crval=[10,10], params=[1])
        except ValueError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        else:
            raise RuntimeError ("     Unexpected Pass ... FAIL")

        try:
           #14293 - validate params argument: params[] = empty array
           print('     coord_dd = dmCoordCreate (cols[1], "wcs_coord", "", cptnames=["IV1", "IV2"], transform="TAN", crpix=[1,1], cdelt=[.1, .1], crval=[10,10], params=[])', file=self.fh)
           coord_dd = dmCoordCreate (cols[1], "wcs_coord", "", cptnames=["IV1", "IV2"], transform="TAN", crpix=[1,1], cdelt=[.1, .1], crval=[10,10], params=[])
        except ValueError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        else:
            raise RuntimeError ("     Unexpected Pass ... FAIL")

        try:
           #14293 - validate params argument: params[] = 2D list
           print('     coord_dd = dmCoordCreate (cols[1], "wcs_coord", "", cptnames=["IV1", "IV2"], transform="TAN", crpix=[1,1], cdelt=[.1, .1], crval=[10,10], params=[[1,2],[2,4]])', file=self.fh)
           coord_dd = dmCoordCreate (cols[1], "wcs_coord", "", cptnames=["IV1", "IV2"], transform="TAN", crpix=[1,1], cdelt=[.1, .1], crval=[10,10], params=[[1,2],[2,4]])
        except ValueError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        else:
            raise RuntimeError ("     Unexpected Pass ... FAIL")

        try:
           #14293 - validate params argument: params[] = scalar
           print('     coord_dd = dmCoordCreate (cols[1], "wcs_coord", "", cptnames=["IV1", "IV2"], transform="TAN", crpix=[1,1], cdelt=[.1, .1], crval=[10,10], params=7)', file=self.fh)
           coord_dd = dmCoordCreate (cols[1], "wcs_coord", "", cptnames=["IV1", "IV2"], transform="TAN", crpix=[1,1], cdelt=[.1, .1], crval=[10,10], params=7)
        except ValueError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        else:
            raise RuntimeError ("     Unexpected Pass ... FAIL")





    # ----------------------------------------------------------------------
    # dmCopyGeneric
    # ----------------------------------------------------------------------
    def test_124( self ):
        """
        dmCopyGeneric - tests dmCopyGeneric routine by reversing the
        order of three columns- a scalar double, array of longs, and
        vector of floats. All other columns maintain their original 
        order.  
        """

        print("Running Test 124", file=self.fh)

        infile  = self.indir + self.infiles[0]
        outfile = self.outdir + self.outfiles[10]

        # Open input file
        tab1  = dmTableOpen(infile)
        destds = dmDatasetCreate( outfile )
        tab2 = dmBlockCreateGenCopy( destds, "TABONE", tab1, copydata=True)

        # get column discriptors
        in_d1 = dmTableOpenColumn(tab1, "DCOL")
        in_d2 = dmTableOpenColumn(tab1, "JACOL")
        in_d3 = dmTableOpenColumn(tab1, "SKY")
        out_d1 = dmTableOpenColumn(tab2, "DCOL")
        out_d2 = dmTableOpenColumn(tab2, "JACOL")
        out_d3 = dmTableOpenColumn(tab2, "SKY")

        cnt = dmTableGetNoRows(tab1)

        for rr in np.arange(cnt,0,-1):
           dmTableSetRow(tab1, rr)
           dmTableSetRow(tab2, cnt-rr+1)
           dmCopyGeneric(in_d1,out_d1)
           dmCopyGeneric(in_d2,out_d2)
           dmCopyGeneric(in_d3,out_d3)

        dmBlockClose(tab1)
        dmBlockClose(tab2)

    # ----------------------------------------------------------------------
    # dmTanPixToWorld and dmTanWorldToPix
    # ----------------------------------------------------------------------
    def test_125( self ):
        """
        dmTanPixToWorld/dmTanWorldToPix - tests the tangent plane conversions
        from pixel to world coordinate system and back.
        """

        print("Running Test 125", file=self.fh)

        # Test inputs:
        asp_1103 = [79.2024, 45.9832, 0]
        asp_2556 = [134.83626,-47.5038523, 0]
        crpix = [4096.5, 4096.5]
        cdelt = [-0.000136667, 0.000136667]
        pixel = [[0.00,0.00],[1000,1000],[2000,2000],
                 [3000,3000],[4000,4000],[5000,5000],
                 [6000,6000],[7000,7000],[8000,8000],
                 [8192.00,8192.00],[4096.50,4096.50],[4555.40,3546.30],
                 [5143.80,7330.68],[3951.10,2754.95],[4418.70,6728.06],
                 [6141.40,5097.63],[3147.50,4138.60]]

        # Expected results (world)
        exp_1103_w = [[79.999983,45.420586],[79.806778,45.558425],[79.612610,45.695946],
                      [79.417477,45.833143],[79.221375,45.970010],[79.024303,46.106540],
                      [78.826257,46.242727],[78.627236,46.378564],[78.427236,46.514046],
                      [78.388724,46.540017],[79.202400,45.983200],[79.112266,45.907970],
                      [78.994760,46.425009],[79.230903,45.799851],[79.138615,46.342825],
                      [78.799219,46.119312],[79.389068,45.988802]]

        exp_2256_w = [[135.673887,-48.060647],[135.467771,-47.925303],[135.262718,-47.789582],
                      [135.058724,-47.653492],[134.855788,-47.517039],[134.653905,-47.380229],
                      [134.453000,-47.243000],[134.253287,-47.105567],[134.054545,-46.967728],
                      [134.016506,-46.941225],[134.836260,-47.503852],[134.743288,-47.579009],
                      [134.626153,-47.061663],[134.865779,-47.687194],[134.771520,-47.144191],
                      [134.423644,-47.366291],[135.028228,-47.497938]]

        # Comparison tolerance
        tolerance = 1e-4

        print(" dmTanPixToWorld()/dmTanWorldToPix()", file=self.fh) 
        print("   Round robin coordinate conversion: pixel => world => pixel", file=self.fh) 

        print("   + use RA/DEC from obsid 1103", file=self.fh) 
        for r in range(0,len(pixel)):
           tpix = pixel[r]
           exp_w = exp_1103_w[r]

           wout = dmTanPixToWorld(tpix, asp_1103, crpix, cdelt)
           pout = dmTanWorldToPix(wout, asp_1103, crpix, cdelt)
           
           world_ok = self.t125_compare( exp_w, wout, tolerance )
           pix_ok   = self.t125_compare( tpix,  pout, tolerance )
           print("      orig pix = (%6.1f,%6.1f) -> world = %s -> pix = %s" % (tpix[0],tpix[1],world_ok,pix_ok), file=self.fh)

        print("   + use RA/DEC from obsid 2556", file=self.fh) 
        for r in range(0,len(pixel)):
           tpix = pixel[r]
           exp_w = exp_2256_w[r]

           wout = dmTanPixToWorld(tpix, asp_2556, crpix, cdelt)
           pout = dmTanWorldToPix(wout, asp_2556, crpix, cdelt)

           world_ok = self.t125_compare( exp_w, wout, tolerance )
           pix_ok   = self.t125_compare( tpix,  pout, tolerance )
           print("      orig pix = (%6.1f,%6.1f) -> world = %s -> pix = %s" % (tpix[0],tpix[1],world_ok,pix_ok), file=self.fh)

    def t125_compare( self, expval, datval, tolerance ):

        if ( ( abs(datval[0] - expval[0]) < tolerance ) and ( abs(datval[1] - expval[1]) < tolerance ) ):
            outstr = "OK"
        else:
            outstr = "Not-OK; expected=({0:9.6f},{1:9.6f}) result=({2:9.6f},{3:9.6f})".format(expval[0],expval[1],datval[0],datval[1])

        return(outstr)

    # ----------------------------------------------------------------------
    # dmTableReadRegion and dmTableWriteRegion 
    # ----------------------------------------------------------------------
    def test_126( self ):
        """
        dmTableReadRegion/dmTableWriteRegion - tests writing and reading of
        region block.
        """

        print("Running Test 126", file=self.fh)

        infile  = self.indir + self.infiles[5]
        outfile = self.outdir + self.outfiles[11]

        # copy input file to output location for update
        os.system("cp " + infile + " " + outfile)

        try:
           print("\n     try opening REGION block from file", file=self.fh)
           t2=dmTableOpen(outfile+"[REGION]")
        except IOError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
        else:
           print("      FAIL - outfile should not have REGION block", file=self.fh)
           dmTableClose(t2)

        # add region  
        print("\n     add region for Sky column", file=self.fh)
        ds=dmDatasetOpen(outfile, update=True)
        tt=dmDatasetGetBlock(ds,2)
        desc=dmTableOpenColumn(tt,"sky")
        print("     got column %s " % dmGetName(desc), file=self.fh)
        region = regParse("circle(4412,4044,100)");
        bl=dmTableWriteRegion(ds,b"REGION",desc,region)
        dmDatasetClose(ds)

        print("\n     try opening REGION block from file again", file=self.fh)
        t2=dmTableOpen(outfile+"[REGION]")
        rr=dmTableReadRegion(t2)
        rs = regRegionString(rr)
        print("     print region string: %s" % rs, file=self.fh) 
        dmTableClose(t2)

        ds2 = dmDatasetOpen(outfile, update=True)
        reg2 = regParse("box(4035.5,4124,139,40,0)")
        desc2 = dmDescriptor(None)
        try:
           print("\n     try w/o name for block", file=self.fh)
           bl=dmTableWriteRegion(ds2,"",desc2,reg2)
        except ValueError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise

        try:
           reg3 = Region()
           print("\n     try w/ empty region", file=self.fh)
           bl=dmTableWriteRegion(ds2,"",desc2,reg3)
        except ValueError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise

        try:
           print("\n     try w/o desc", file=self.fh)
           bl=dmTableWriteRegion(ds2,"REG2",desc2,reg2)
        except ValueError as e:
            print("    ", e, file=self.fh)
            print("     Expected ... OK", file=self.fh)
            pass
        except:
            raise
           
        dmDatasetClose(ds2) 
        print("\n     try opening REG2 block from file", file=self.fh)
        t2=dmTableOpen(outfile+"[REG2]")
        rr=dmTableReadRegion(t2)
        rs = regRegionString(rr)
        print("     print region string: %s" % rs, file=self.fh) 
        dmTableClose(t2)


    # ----------------------------------------------------------------------
    # dmBlockCreateSubspaceCpt and dmBlockCreateEmptySubspaceCpt
    # ----------------------------------------------------------------------
    def test_127( self ):
        """
        dmBlockCreateSubspaceCpt/dmBlockCreateEmptySubspaceCpt- tests
        addition of subspace components via specified methods
        """

        print("", file=self.fh)
        print("Running Test 127", file=self.fh)
        print("", file=self.fh)

        outfile = self.outdir + self.outfiles[13]

        ds=dmDatasetCreate(outfile)
        bl=dmDatasetCreateTable(ds,"DATA")
        [c1] = dmColumnCreate(bl, b"col1", np.float64)
        [c2] = dmColumnCreate(bl,"vect",dtype=[np.float32],cptnames=[u"a",u"b"])  # force Unicode string form.
        d1=dmGetCpt(c2,1)
        d2=dmGetCpt(c2,2)
        dmSetData(c1,[5.3,78.1,124.33])
        dmSetData(d1,[4001,5001,6001])
        dmSetData(d2,[4400,4600,4300])
        xx =dmSubspaceColOpen(bl,"col1")
        dmSubspaceColSet(xx,15,100)
        print(" no. subspace cpts   : %d" %dmBlockGetNoSubspaceCpts(bl), file=self.fh)
        print(" current subspace cpt: %d" %dmBlockGetCurrSubspaceCpt(bl), file=self.fh)

        # should seed w/ values from 1st cpt subspace 
        dmBlockCreateSubspaceCpt(bl)
        print(" no. subspace cpts   : %d" %dmBlockGetNoSubspaceCpts(bl), file=self.fh)
        print(" current subspace cpt: %d" %dmBlockGetCurrSubspaceCpt(bl), file=self.fh)

        # should seed w/ values but overwrite w/ specified 
        dmBlockCreateSubspaceCpt(bl)
        yy = dmSubspaceColOpen(bl,"col1")
        dmSubspaceColSet(yy,0,60)
        print(" no. subspace cpts   : %d" %dmBlockGetNoSubspaceCpts(bl), file=self.fh)
        print(" current subspace cpt: %d" %dmBlockGetCurrSubspaceCpt(bl), file=self.fh)

        # should not seed values 
        dmBlockCreateEmptySubspaceCpt(bl)
        print(" no. subspace cpts   : %d" %dmBlockGetNoSubspaceCpts(bl), file=self.fh)
        print(" current subspace cpt: %d" %dmBlockGetCurrSubspaceCpt(bl), file=self.fh)

        # should not seed values but overwrite w/ specified 
        dmBlockCreateEmptySubspaceCpt(bl)
        zz = dmSubspaceColOpen(bl,"col1")
        dmSubspaceColSet(zz,45, 150)
        print(" no. subspace cpts   : %d" %dmBlockGetNoSubspaceCpts(bl), file=self.fh)
        print(" current subspace cpt: %d" %dmBlockGetCurrSubspaceCpt(bl), file=self.fh)

        # check values of subspace cpts 
        (ncpts, ncols, descs) = dmBlockGetSubspace(bl)
        
        print("", file=self.fh)
        print("  cpt   column    min     max  ", file=self.fh)
        print("  ---   ------    ---     ---  ", file=self.fh)
        for r in range(1, ncpts+1):
           dmBlockSetSubspaceCpt(bl,r)
           (mins,maxes) = dmSubspaceColGet(descs[0])
           if len(mins) > 0:
              print("   %d    %5s  %7.2f  %7.2f" % (r, dmGetName(descs[0]), mins[0], maxes[0]), file=self.fh)
           else:
              print("   %d    %5s  default  default" % (r, dmGetName(descs[0])), file=self.fh)
  
        dmDatasetClose(ds)

    # ----------------------------------------------------------------------
    # dmBlockIntersectSubspace and dmBlockMergeSubspace
    # ----------------------------------------------------------------------
    def test_128( self ):
        """
        dmBlockIntersectSubspace/dmBlockMergeSubspace- tests
        addition of subspace components via specified methods
        """

        print("", file=self.fh)
        print("Running Test 128", file=self.fh)
        print("", file=self.fh)

        infile  = self.indir + self.infiles[6]
        outfile1 = self.outdir + self.outfiles[14]
        outfile2 = self.outdir + self.outfiles[15]
        outfile3 = self.outdir + self.outfiles[16]
        os.system("cp " + infile + " " + outfile1)
        os.system("cp " + infile + " " + outfile2)
        os.system("cp " + infile + " " + outfile3)

        b1 = dmTableOpen(outfile1+"[block1]",update=True)  
        b2 = dmTableOpen(outfile1+"[block2]",update=True)  
        b3 = dmTableOpen(outfile1+"[block3]",update=True)  

        print("Intersect blocks within same file", file=self.fh)
        dmBlockIntersectSubspace(b1, b2, b3); 

        # check values of subspace cpts 
        (ncpts, ncols, descs) = dmBlockGetSubspace(b3)
        
        print("", file=self.fh)
        print("  cpt   column    min     max  ", file=self.fh)
        print("  ---   ------    ---     ---  ", file=self.fh)
        for r in range(1, ncpts+1):
           dmBlockSetSubspaceCpt(b3,r)
           (mins,maxes) = dmSubspaceColGet(descs[0])
           if len(mins) > 0:
              print("   %d    %5s  %7.2f  %7.2f" % (r, dmGetName(descs[0]), mins[0], maxes[0]), file=self.fh)
           else:
              print("   %d    %5s  default  default" % (r, dmGetName(descs[0])), file=self.fh)
  

        print("", file=self.fh)
        print("Intersect blocks from different file", file=self.fh)
        c0 = dmTableOpen(outfile2+"[block0]",update=True)
        c3 = dmTableOpen(outfile2+"[block3]",update=True)
        dmBlockIntersectSubspace(b3,c0, c3); 

        # check values of subspace cpts 
        (ncpts, ncols, descs) = dmBlockGetSubspace(c3)
        
        print("", file=self.fh)
        print("  cpt   column    min     max  ", file=self.fh)
        print("  ---   ------    ---     ---  ", file=self.fh)
        for r in range(1, ncpts+1):
           dmBlockSetSubspaceCpt(c3,r)
           (mins,maxes) = dmSubspaceColGet(descs[0])
           if len(mins) > 0:
              print("   %d    %5s  %7.2f  %7.2f" % (r, dmGetName(descs[0]), mins[0], maxes[0]), file=self.fh)
           else:
              print("   %d    %5s  default  default" % (r, dmGetName(descs[0])), file=self.fh)
      
        dmBlockClose(b1) 
        dmBlockClose(b3) 
        dmBlockClose(c0) 
        dmBlockClose(c3) 

        print("", file=self.fh)

        d0 = dmTableOpen(outfile3+"[block0]",update=True)
        d1 = dmTableOpen(outfile3+"[block1]",update=True)
        d2 = dmTableOpen(outfile3+"[block2]",update=True)
        d3 = dmTableOpen(outfile3+"[block3]",update=True)

        print("Merge blocks from same file", file=self.fh)
        print("", file=self.fh)

        dmBlockMergeSubspace(d1, d2, d3) 

        # check values of subspace cpts 
        (ncpts, ncols, descs) = dmBlockGetSubspace(d3)
        
        print("", file=self.fh)
        print("  cpt   column    min     max  ", file=self.fh)
        print("  ---   ------    ---     ---  ", file=self.fh)
        for r in range(1, ncpts+1):
           dmBlockSetSubspaceCpt(d3,r)
           (mins,maxes) = dmSubspaceColGet(descs[0])
           if len(mins) > 0:
              print("   %d    %5s  %7.2f  %7.2f" % (r, dmGetName(descs[0]), mins[0], maxes[0]), file=self.fh)
           else:
              print("   %d    %5s  default  default" % (r, dmGetName(descs[0])), file=self.fh)
      
        print("", file=self.fh)
        print("Merge blocks from different files", file=self.fh)

        dmBlockMergeSubspace(b2, d0, d0) 

        # check values of subspace cpts 
        (ncpts, ncols, descs) = dmBlockGetSubspace(d0)
        
        print("", file=self.fh)
        print("  cpt   column    min     max  ", file=self.fh)
        print("  ---   ------    ---     ---  ", file=self.fh)
        for r in range(1, ncpts+1):
           dmBlockSetSubspaceCpt(d0,r)
           (mins,maxes) = dmSubspaceColGet(descs[0])
           if len(mins) > 0:
              print("   %d    %5s  %7.2f  %7.2f" % (r, dmGetName(descs[0]), mins[0], maxes[0]), file=self.fh)
           else:
              print("   %d    %5s  default  default" % (r, dmGetName(descs[0])), file=self.fh)

        dmBlockClose(d0)
        dmBlockClose(d1)
        dmBlockClose(d2)
        dmBlockClose(d3)

        dmBlockClose(b2) 


    # ----------------------------------------------------------------------
    # dmSubspaceColCreateRegion
    # ----------------------------------------------------------------------
    def test_129( self ):
        """
        dmSubspaceColCreateRegion tests
        """

        print("", file=self.fh)
        print("Running Test 129", file=self.fh)
        print("", file=self.fh)

        infile  = self.indir + self.infiles[6]
        outfile = self.outdir + self.outfiles[17]
        os.system("cp " + infile + " " + outfile)

        t = dmTableOpen(outfile,update=True)
        d=dmSubspaceColCreateRegion(t, b"regiona", ["x","y"], np.float32, b"px", "circle(4100,4100,25)")

        print("  region using a string region specification", file=self.fh)

        reg = dmSubspaceColGetRegion( d )
        print("             - region object: %s " % regRegionString( reg ), file=self.fh)
        dmBlockClose(t)

        t = dmTableOpen(outfile,update=True)
        r = regParse("ellipse(4200,4200,100,50,30)-box(4200,4200,10,10)")
        d=dmSubspaceColCreateRegion(t, "regionb", ["x","y"], np.float32, "px", r)
        print("", file=self.fh)
        print("  region using a regRegion struct", file=self.fh)
        reg = dmSubspaceColGetRegion( d )
        print("             - region object: %s " % regRegionString( reg ), file=self.fh)
        dmBlockClose(t)
         
        t = dmTableOpen(outfile)
        sc = dmSubspaceColOpen(t,"regiona")
        sreg = dmSubspaceColGetRegion( sc )
        print("", file=self.fh)
        print("  get regions from output file", file=self.fh)
        print("", file=self.fh)
        print("  %s : %s " % (dmGetName(sc), regRegionString(sreg)), file=self.fh)
        sc = dmSubspaceColOpen(t,"regionb")
        sreg = dmSubspaceColGetRegion( sc )
        print("", file=self.fh)
        print("  %s : %s " % (dmGetName(sc), regRegionString(sreg)), file=self.fh)
        print("", file=self.fh)

    # ----------------------------------------------------------------------
    # dmGetData: Tri-State boolean values
    # ----------------------------------------------------------------------
    def test_130( self ):
        """
        Test of Tri-State boolean value transfer from C layer to python.
          o NULL values should be translated to False.

        NOTE: Test 111 exercises dmGetData, including logical column,
              but the values are 2-state.  Modifying that data file 
              to include a NULL state, effects many unrelated test 
              outputs due to the change data value.
              We opt to add this test instead to minimize impact.
        """

        print("", file=self.fh)
        print("Running Test 130", file=self.fh)
        print("", file=self.fh)
        print("  Tri-State boolean data.", file=self.fh)
        print("    3rd row is NULL in file, translated to False.", file=self.fh)

        infile  = self.indir + self.infiles[7]
        outfile = self.outdir + self.outfiles[18]
        os.system("cp " + infile + " " + outfile)

        t = dmTableOpen(outfile,update=True)

        lcol_dd = dmTableOpenColumn (t, "lcol")

        print("  data = dmGetData (lcol_dd)", file=self.fh)
        try:
            data = dmGetData (lcol_dd, nrows=4)
        except:
            raise
        else:
            print(data, file=self.fh)



    # ----------------------------------------------------------------------
    #
    # ----------------------------------------------------------------------
    def test_create_keys( self, b ):
        """
        Write sample set of keywords to provided block.
        """
        if b is None:
            raise Exception()

        # Write some header keys
        ival = 1001
        fval = np.float32(3.14159)
        dval = 3.14159
        sval = "NOVA"

        iarr = np.array( [1,2,3], dtype=np.int32 )
        farr = np.array( [11.1,22.2,33.3], dtype=np.float32 )
        sarr = np.array( ["PIE","PI","Py"], dtype='S3' )

        try: #Boolean keys
            bval = True
            k = dmKeyWrite(b, "BOOLTKEY", bval )
            bval = False
            k = dmKeyWrite(b, "BOOLFKEY", bval )
        except:
            raise

        try: #Integer key
            k = dmKeyWrite(b, "IVALKEY", ival , unit="cm" )
        except:
            raise

        try: #Float key
            k = dmKeyWrite(b, "FVALKEY", fval , desc="muffins")
        except:
            raise

        try: #Double key
            k = dmKeyWrite(b, "DVALKEY", dval )
        except:
            raise

        try: #String key
            k = dmKeyWrite(b, "SVALKEY", sval )
        except:
            raise

        try: #Integer Array key
            k = dmKeyWrite(b, "IARRKEY", iarr, unit="m", desc="distance along axis N" )
        except:
            raise

        try: #Float Array key
            k = dmKeyWrite(b, "FARRKEY", farr )
        except:
            raise

        try: #String Array key
            k = dmKeyWrite(b, "SARRKEY", sarr )
        except:
            raise

    # ----------------------------------------------------------------------
    #
    # ----------------------------------------------------------------------
    def test_create_columns( self, tab ):
        """
        Exercises the dmColumnCreate function.
        """
        if tab is None:
            raise Exception()


        print("  col = dmColumnCreate( tab, \"SCOL\", np.string_ , itemsize=10 )   # good minimal input (string)", file=self.fh) 
        try:
            col = dmColumnCreate( tab, b"SCOL", np.string_ , itemsize=10)
        except:
            raise

        print("  col = dmColumnCreate( tab, \"ICOL\", np.short )                   # good minimal input (short)", file=self.fh)
        try:
            col = dmColumnCreate( tab, "ICOL", np.short )
        except:
            raise

        print("  col = dmColumnCreate( tab, \"JCOL\", np.int32 )                   # good minimal input (long)", file=self.fh)
        try:
            col = dmColumnCreate( tab, "JCOL", np.int32 )
        except:
            raise

        print("  col = dmColumnCreate( tab, \"FCOL\", dtype=np.float32, unit=\"mag\", desc=\"Instr. magnitude\" ) # include optl (float)", file=self.fh)
        try:
            col = dmColumnCreate( tab, "FCOL", dtype=np.float32, unit="mag", desc="Instr. magnitude" )
        except:
            raise

        print("  col = dmColumnCreate( tab, \"DCOL\", np.float64 )                 # good minimal input (double)", file=self.fh)
        try:
            col = dmColumnCreate( tab, "DCOL", np.float64 )
        except:
            raise

        print("  col = dmColumnCreate( tab, \"BCOL\", np.byte )                    # good minimal input (byte)", file=self.fh)
        try:
            col = dmColumnCreate( tab, "BCOL", np.byte )
        except:
            raise
        
        print("  col = dmColumnCreate( tab, \"LCOL\", np.bool_ )                  # good minimal input (bool)", file=self.fh)
        try:
            col = dmColumnCreate( tab, "LCOL", np.bool_ )
        except:
            raise

        print("  col = dmColumnCreate( tab, \"UICOL\", np.ushort )                # good minimal input (ushort)", file=self.fh)
        try:
            col = dmColumnCreate( tab, "UICOL", np.ushort )
        except:
            raise

        print("  col = dmColumnCreate( tab, \"UJCOL\", np.uint )                  # good minimal input (ulong)", file=self.fh)
        try:
            col = dmColumnCreate( tab, "UJCOL", np.uint )
        except:
            raise

        print("  col = dmColumnCreate( tab, \"IACOL\", np.short, shape=[5] )       # good array input (short)", file=self.fh)
        try:
            col = dmColumnCreate( tab, "IACOL", np.short, shape=[5])
        except:
            raise

        dims = np.array([5], dtype=np.int32)
        print("  col = dmColumnCreate( tab, \"JACOL\", np.int32, shape=<arr> )     # good array input (long)", file=self.fh)
        try:
            col = dmColumnCreate( tab, "JACOL", np.int32, shape=dims )
        except:
            raise

        print("  col = dmColumnCreate( tab, \"FACOL\", dtype=np.float32, shape=5 ) # good array input (float)", file=self.fh)
        try:
            col = dmColumnCreate( tab, "FACOL", dtype=np.float32, shape=5 )
        except:
            raise

        print("  col = dmColumnCreate( tab, \"DACOL\", np.float64, shape=dims )    # good minimal input (double)", file=self.fh)
        try:
            col = dmColumnCreate( tab, "DACOL", np.float64, shape=dims )
        except:
            raise


        print("  col = dmColumnCreate( tab, \"IVEC\", np.short, cptnames=[\"IV1\",\"IV2\"] )  # good vector input (short)", file=self.fh)
        try:
            col = dmColumnCreate( tab, "IVEC", np.short, cptnames=[b"IV1",b"IV2"] )  # force Byte string form.
            #col = dmColumnCreate( tab, "IVEC", np.short, cptnames=["IV1","IV2"] )
        except:
            raise

        # ****************************************
        # Multi-Column
        # ****************************************

        print(' cols = dmColumnCreate( tab, ["FACOL_M1", "DACOL_M1"], dtype=[np.float32, np.float64] shape=[5,dims])   # good shapes', file=self.fh)
        try:
            cols = dmColumnCreate( tab, [b"FACOL_M1", b"DACOL_M1"], dtype=[np.float32, np.float64], shape=[5,dims])
            if len (cols) != 2:
                raise RuntimeError ("Expected column length to be 2. Got %d"%len(cols))
        except:
            raise

        print('  cols = dmColumnCreate( tab, ["SCOL_M1","ICOL_M1","SCOL_M2"], [np.string_,np.short,np.string] , itemsize=[10,20] )   # good multiple itemsize', file=self.fh)
        try:
            cols = dmColumnCreate( tab, ["SCOL_M1","ICOL_M1","SCOL_M2"], [np.string_,np.short,np.string_] , itemsize=[10,0,20] )
            if len (cols) != 3:
                raise RuntimeError ("Expected column length to be 3. Got %d"%len(cols))
        except:
            raise

        print('  cols = dmColumnCreate( tab, ["SCOL_M3","ICOL_M2","JCOL_M1"], [np.string_,np.short,np.int32] , itemsize=15 )   # good single itemsize', file=self.fh)
        try:
            cols = dmColumnCreate( tab, ["SCOL_M3","ICOL_M2","JCOL_M1"], [np.string_,np.short,np.int32] , itemsize=15 )
            if len (cols) != 3:
                raise RuntimeError ("Expected column length to be 3. Got %d"%len(cols))
        except:
            raise


        print('  col = dmColumnCreate( tab, ["FCOL_M2","DCOL_M2","BCOL_M2"], dtype=[np.float32,np.float64,np.byte], unit=["mag","","bytes"], desc=["Instr. magnitude","Extra Data",""] ) # good descriptions and units', file=self.fh)
        try:
            cols = dmColumnCreate( tab, ["FCOL_M2","DCOL_M2","BCOL_M2"], dtype=[np.float32,np.float64,np.byte], unit=["mag","","bytes"], desc=["Instr. magnitude","Extra Data",""] )
            if len (cols) != 3:
                raise RuntimeError ("Expected column length to be 3. Got %d"%len(cols))
        except:
            raise

        print('  col = dmColumnCreate( tab, ["IVEC_M1", "IVEC_M2"], [np.short, np.short], cptnames=[["IV1_M1","IV2_M1"],["IV1_M2","IV2_M2","IV3_M2"]] )  # good multiple vector component names', file=self.fh)
        try:
#            cols = dmColumnCreate( tab, ["IVEC_M1", "IVEC_M2"], [np.short, np.short], cptnames=[["IV1_M1","IV2_M1"],["IV1_M2","IV2_M2","IV3_M2"]] )
            cols = dmColumnCreate( tab, ["IVEC_M1", "IVEC_M2"], [np.short, np.short], cptnames=[["IV1_M1","IV2_M1"],["IV1_M2","IV2_M2"]] )
            if len (cols) != 2:
                raise RuntimeError ("Expected column length to be 2. Got %d"%len(cols))
        except:
            raise

        print('cols = dmColumnCreate( tab, ["DCOL_M3", "DCOL_M4"], [np.float64, np.float64], shape=[dims], desc="test1", unit=["","deg"] )  # good - too few shapes and descriptions', file=self.fh)
        try:
            cols = dmColumnCreate( tab, ["DCOL_M3", "DCOL_M4"], [np.float64, np.float64], shape=[dims], desc="test1", unit=["","deg"] )
            if len (cols) != 2:
                raise RuntimeError ("Expected column length to be 2. Got %d"%len(cols))
        except:
            raise

        print('  col = dmColumnCreate( tab, ["FVEC_M1", "FVEC_M2", "FVEC_M3"], [np.float32, np.float32], cptnames=["FV1",["FV3","FV4"],"FV5"] )  # good multiple vector component names', file=self.fh)
        try:
            cols = dmColumnCreate( tab, ["FVEC_M1", "FVEC_M2", "FVEC_M3"], [np.float32, np.float32, np.float32], cptnames=["FV1",["FV3","FV4"],"FV5"] )
            if len (cols) != 3:
                raise RuntimeError ("Expected column length to be 3. Got %d"%len(cols))
        except:
            raise


        # ****************************************
        # Varlen Scalar Array Columns
        # ****************************************

        print('  col = dmColumnCreate()  # dmDOUBLE varlen scalar array', file=self.fh)
        try:
            col = dmColumnCreate( tab, "VAR_DBL", np.float64, unit="vunit", desc="vdesc", shape=np.array(10), varlen=True )
        except:
            raise

        print('  col = dmColumnCreate()  # dmFLOAT varlen scalar array', file=self.fh)
        try:
            col = dmColumnCreate( tab, "VAR_FLT", np.float32, unit="vunit", desc="vdesc", shape=np.array(10), varlen=True )
        except:
            raise

        print('  col = dmColumnCreate()  # dmLONG varlen scalar array', file=self.fh)
        try:
            col = dmColumnCreate( tab, "VAR_LNG", np.int32, unit="vunit", desc="vdesc", shape=np.array(10), varlen=True )
        except:
            raise

        print('  col = dmColumnCreate()  # dmSHORT varlen scalar array', file=self.fh)
        try:
            col = dmColumnCreate( tab, "VAR_SHR", np.int16, unit="vunit", desc="vdesc", shape=np.array(10), varlen=True )
        except:
            raise

        print('  col = dmColumnCreate()  # dmBYTE varlen scalar array', file=self.fh)
        try:
            col = dmColumnCreate( tab, "VAR_BYT", np.uint8, unit="vunit", desc="vdesc", shape=np.array(10), varlen=True )
        except:
            raise

        print('  col = dmColumnCreate()  # dmBOOL varlen scalar array', file=self.fh)
        try:
            col = dmColumnCreate( tab, "VAR_BOO", np.bool_, unit="vunit", desc="vdesc",  shape=np.array(10), varlen=True )
        except:
            raise


        # ****************************************
        # Varlen VECTOR Array Columns
        # ****************************************



        print('  col = dmColumnCreate()  # dmDOUBLE varlen vector array', file=self.fh)
        try:
            col = dmColumnCreate( tab, "VARVEC_DBL", np.float64,  cptnames=["VV1_DBL","VV2_DBL"], unit="vvunit", desc="vvdesc", shape=np.array(8), varlen=True )
        except:
            raise

        print('  col = dmColumnCreate()  # dmFLOAT varlen vector array', file=self.fh)
        try:
            col = dmColumnCreate( tab, "VARVEC_FLT", np.float32,  cptnames=["VV1_FLT","VV2_FLT"], unit="vvunit", desc="vvdesc", shape=np.array(8), varlen=True )
        except:
            raise


        print('  col = dmColumnCreate()  # dmLONG varlen vector array', file=self.fh)
        try:
            col = dmColumnCreate( tab, "VARVEC_LNG", np.int32,  cptnames=["VV1_LNG","VV2_LNG"], unit="vvunit", desc="vvdesc",  shape=np.array(8), varlen=True )
        except:
            raise

        print('  col = dmColumnCreate()  # dmSHORT varlen vector array', file=self.fh)
        try:
            col = dmColumnCreate( tab, "VARVEC_SHR", np.int16,  cptnames=["VV1_SHR","VV2_SHR"], unit="vvunit", desc="vvdesc", shape=np.array(8), varlen=True )
        except:
            raise


        print('  col = dmColumnCreate()  # dmBYTE varlen vector array', file=self.fh)
        try:
            col = dmColumnCreate( tab, "VARVEC_BYT", np.int8,  cptnames=["VV1_BYT","VV2_BYT"], unit="vvunit", desc="vvdesc", shape=np.array(8), varlen=True )
        except:
            raise


        print('  col = dmColumnCreate()  # dmBOOL varlen vector array', file=self.fh)
        try:
            col = dmColumnCreate( tab, "VARVEC_BOO", np.bool_,  cptnames=["VV1_BOO","VV2_BOO"], unit="vvunit", desc="vvdesc", shape=np.array(8), varlen=True )
        except:
            raise




    # ----------------------------------------------------------------------
    #
    # ----------------------------------------------------------------------
    def test_format_range( self, rangemin, rangemax ):
        """
        Generate a string representation of a range.
        """
        res = [str(rangemin),str(rangemax)]

        ityparr = [np.int16, np.int32, np.int64, np.uint8, np.uint16, np.uint32]
        ftyparr = [np.float32, np.float64]

        if ( type(rangemin) is np.string_ ) or ( type(rangemin) is np.bool_ ) or ( rangemin is None ):
            return "-"

        found = False
        for dtype in ftyparr:
            if ( type(rangemin) is dtype ):
                found = True
                if ( rangemin == np.finfo(dtype).min ):
                    res[0] = ""
                if ( rangemax == np.finfo(dtype).max):
                    res[1] = ""

        if ( not found ):
            for dtype in ityparr:
                if ( type(rangemin) is dtype ):
                    found = True
                    if ( rangemin == np.iinfo(dtype).min ):
                        res[0] = ""
                    if ( rangemax == np.iinfo(dtype).max):
                        res[1] = ""
        
        
        outstr =  ":".join(res)
        if ( outstr == ":" ):
            outstr = "DEFAULT"

        return outstr


    # ----------------------------------------------------------------------
    #
    # ----------------------------------------------------------------------
    def test_print_key( self, key ):
        """
        Display keyword info.. formatted nicely.
        """

        name  = dmGetName( key )
        unit  = dmGetUnit( key )
        dtype = self._get_dtype_string( dmGetDataType( key ) )
        desc  = dmGetDesc( key )
        
        print("       %-15s %-10s %-15s %-25s" % (name, unit, dtype, desc), file=self.fh)


# ------------------------------------------------------------------------------
#
# ------------------------------------------------------------------------------
if __name__ == '__main__':
    t = TestCXCDM(*sys.argv[1:])
    print(t)

    anybad = False

    # Run the set of tests
    try:
        if ( t.run() == "FAIL" ):
            anybad = True
    except TypeError as e:
        name = ""
        print("    ", e)
        pass
    except:
        raise

    # Run the output files they create
    try:
        if ( t.verify() == "FAIL"):
            anybad = True
    except:
        raise

    if anybad:
        grade = "FAIL"
    else:
        grade = "PASS"

    print()
    print("CXCDM Module Tests: %s" % grade)
