Commit c6529af4 authored by Hoek, Steven's avatar Hoek, Steven
Browse files

Test scripts developed and bugs fixed; arguments of methods __init__ had to be given default values

parent a037d9b4
eclipse.preferences.version=1 eclipse.preferences.version=1
encoding//formats/bilraster.py=utf-8
encoding//formats/bsqraster.py=utf-8 encoding//formats/bsqraster.py=utf-8
encoding//toolbox/scalelib.py=latin1 encoding//toolbox/scalelib.py=latin1
from . import formats
from . import toolbox
...@@ -7,7 +7,7 @@ from .gridenvelope2d import GridEnvelope2D; ...@@ -7,7 +7,7 @@ from .gridenvelope2d import GridEnvelope2D;
__author__ = "Steven B. Hoek" __author__ = "Steven B. Hoek"
class AsciiGrid(Raster, GridEnvelope2D): class AsciiGrid(Raster, GridEnvelope2D):
"A raster represented by an ASCII file, with extension 'asc'" """A raster represented by an ASCII file, with extension 'asc'"""
# Data attributes - assign some dummy values for the mean time # Data attributes - assign some dummy values for the mean time
_const = None _const = None
...@@ -24,11 +24,15 @@ class AsciiGrid(Raster, GridEnvelope2D): ...@@ -24,11 +24,15 @@ class AsciiGrid(Raster, GridEnvelope2D):
__mode = 'r'; __mode = 'r';
__digitspercell = 7; __digitspercell = 7;
def __init__(self, filepath, *datatype): def __init__(self, filepath='', *datatype):
# Check input
if filepath == '':
print('File path cannot be an empty string (method __init__).')
# Module wide constants # Module wide constants
self._const = Const() self._const = Const()
self._const.FILEXT = "asc"; self._const.FILEXT = "asc";
self._const.MAXDIGITSPERCELL = 6 # 11 self._const.MAXDIGITSPERCELL = 6 # TODO this is hardcoded - change this
self.name = "dummy." + self._const.FILEXT; self.name = "dummy." + self._const.FILEXT;
# Initialise further # Initialise further
...@@ -176,7 +180,7 @@ class AsciiGrid(Raster, GridEnvelope2D): ...@@ -176,7 +180,7 @@ class AsciiGrid(Raster, GridEnvelope2D):
self.datafile.write(s); self.datafile.write(s);
else: else:
totalwidth = self._const.MAXDIGITSPERCELL - 1 totalwidth = self._const.MAXDIGITSPERCELL - 1
fmtstr = "{:" + str(totalwidth) + ".2f}" fmtstr = "{:" + str(totalwidth) + ".3f}" # TODO format is hardcoded - change this!
for k in range(0, self.ncols): for k in range(0, self.ncols):
s = fmtstr.format(sequence_with_data[k]).rjust(self._const.MAXDIGITSPERCELL + 1); s = fmtstr.format(sequence_with_data[k]).rjust(self._const.MAXDIGITSPERCELL + 1);
self.datafile.write(s); self.datafile.write(s);
......
...@@ -180,7 +180,7 @@ class BandRaster(Raster, GridEnvelope2D): ...@@ -180,7 +180,7 @@ class BandRaster(Raster, GridEnvelope2D):
hf.write(const.NCOLS.upper() + " " + str(self.ncols) + "\n") hf.write(const.NCOLS.upper() + " " + str(self.ncols) + "\n")
hf.write("NBANDS " + str(self.nbands) + "\n") hf.write("NBANDS " + str(self.nbands) + "\n")
hf.write("NBITS " + str(self.nbits) + "\n") hf.write("NBITS " + str(self.nbits) + "\n")
bandrowbytes = self.nbits * self.ncols / 8 bandrowbytes = int(self.nbits * self.ncols / 8)
hf.write("BANDROWBYTES " + str(bandrowbytes) + "\n") hf.write("BANDROWBYTES " + str(bandrowbytes) + "\n")
hf.write("TOTALROWBYTES " + str(self.nbands * bandrowbytes) + "\n") hf.write("TOTALROWBYTES " + str(self.nbands * bandrowbytes) + "\n")
if self.dataformat.lower() == 'i': if self.dataformat.lower() == 'i':
......
...@@ -23,7 +23,14 @@ class BilRaster(BandRaster): ...@@ -23,7 +23,14 @@ class BilRaster(BandRaster):
_const = None _const = None
name = ""; name = "";
def __init__(self, filepath, *dataformat): def __init__(self, filepath='', *dataformat):
# Process input
if filepath == '':
print('File path cannot be an empty string (method __init__).')
if len(dataformat) == 0:
print("Data type 'float' assumed (method __init__).")
dataformat = 'f'
# Initialise super class instance # Initialise super class instance
BandRaster.__init__(self, filepath, dataformat[0]) BandRaster.__init__(self, filepath, dataformat[0])
if self._const == None: if self._const == None:
...@@ -36,7 +43,7 @@ class BilRaster(BandRaster): ...@@ -36,7 +43,7 @@ class BilRaster(BandRaster):
self.name = "dummy." + self._const.DATAFILEXT self.name = "dummy." + self._const.DATAFILEXT
self.currow = -1 self.currow = -1
def open(self, mode, ncols=1, nrows=1, nbands=3, xll=0, yll=0, cellsize=100, nodatavalue=256): def open(self, mode, ncols=1, nrows=1, nbands=1, xll=0, yll=0, cellsize=100, nodatavalue=256):
self.nbits = struct.calcsize(self.dataformat)*8 self.nbits = struct.calcsize(self.dataformat)*8
result = super(BilRaster, self).open(mode, ncols, nrows, nbands, xll, yll, cellsize, nodatavalue); result = super(BilRaster, self).open(mode, ncols, nrows, nbands, xll, yll, cellsize, nodatavalue);
if (mode[0] == 'w'): if (mode[0] == 'w'):
...@@ -135,6 +142,8 @@ class BilRaster(BandRaster): ...@@ -135,6 +142,8 @@ class BilRaster(BandRaster):
if not isinstance(sequence_with_data[0][0], (int, float)) and len(sequence_with_data[0]) != self.nbands: if not isinstance(sequence_with_data[0][0], (int, float)) and len(sequence_with_data[0]) != self.nbands:
raise ValueError("Input sequence elements haven't got the expected number of values") raise ValueError("Input sequence elements haven't got the expected number of values")
else: else:
if isinstance(sequence_with_data, np.ndarray) and len(sequence_with_data.shape) == 1:
sequence_with_data = np.reshape(sequence_with_data, (sequence_with_data.shape[0], 1))
if (not isinstance(sequence_with_data[0][0], (int, float, np.int32, np.float32, np.float64))) or len(sequence_with_data[0]) != self.nbands: if (not isinstance(sequence_with_data[0][0], (int, float, np.int32, np.float32, np.float64))) or len(sequence_with_data[0]) != self.nbands:
raise ValueError("Input sequence elements haven't got the expected number of values") raise ValueError("Input sequence elements haven't got the expected number of values")
if self.nbands > 1 and not self._is_sequence(sequence_with_data[0]): if self.nbands > 1 and not self._is_sequence(sequence_with_data[0]):
......
...@@ -23,7 +23,14 @@ class BsqRaster(BandRaster): ...@@ -23,7 +23,14 @@ class BsqRaster(BandRaster):
_const = None _const = None
name = ""; name = "";
def __init__(self, filepath, *dataformat): def __init__(self, filepath='', *dataformat):
# Check input
if filepath == '':
print('File path cannot be an empty string (method __init__).')
if len(dataformat) == 0:
print("Data type 'float' assumed (method __init__).")
dataformat = 'f'
# Initialise super class instance # Initialise super class instance
BandRaster.__init__(self, filepath, dataformat[0]) BandRaster.__init__(self, filepath, dataformat[0])
if self._const == None: if self._const == None:
...@@ -36,7 +43,7 @@ class BsqRaster(BandRaster): ...@@ -36,7 +43,7 @@ class BsqRaster(BandRaster):
self.name = "dummy." + self._const.DATAFILEXT self.name = "dummy." + self._const.DATAFILEXT
self.currow = -1; self.currow = -1;
def open(self, mode, ncols=1, nrows=1, nbands=3, xll=0, yll=0, cellsize=100, nodatavalue=256): def open(self, mode, ncols=1, nrows=1, nbands=1, xll=0, yll=0, cellsize=100, nodatavalue=256):
result = super(BsqRaster, self).open(mode, ncols, nrows, nbands, xll, yll, cellsize, nodatavalue) result = super(BsqRaster, self).open(mode, ncols, nrows, nbands, xll, yll, cellsize, nodatavalue)
if (mode[0] == 'w'): if (mode[0] == 'w'):
return result return result
...@@ -48,7 +55,7 @@ class BsqRaster(BandRaster): ...@@ -48,7 +55,7 @@ class BsqRaster(BandRaster):
try: try:
bytesperpix = struct.calcsize(self.dataformat) bytesperpix = struct.calcsize(self.dataformat)
except: except:
raise ValueError, "Supplied data format " + str(self.dataformat) + " is invalid" raise ValueError("Supplied data format " + str(self.dataformat) + " is invalid")
# end try # end try
# Check file size matches with size attributes # Check file size matches with size attributes
...@@ -60,9 +67,9 @@ class BsqRaster(BandRaster): ...@@ -60,9 +67,9 @@ class BsqRaster(BandRaster):
checknum = (((filesize / float(self.nbands)) / float(self.nrows)) / float(bytesperpix)) / self.ncols checknum = (((filesize / float(self.nbands)) / float(self.nrows)) / float(bytesperpix)) / self.ncols
if checknum != 1: if checknum != 1:
if fabs(checknum - 1) < 0.00003: if fabs(checknum - 1) < 0.00003:
raise ValueError, "File size and size calculated from attributes only match approximately" raise ValueError("File size and size calculated from attributes only match approximately")
else: else:
raise ValueError, "File size and supplied attributes do not match at all!" raise ValueError("File size and supplied attributes do not match at all!")
# Open the file for reading in binary mode # Open the file for reading in binary mode
try: try:
...@@ -93,7 +100,7 @@ class BsqRaster(BandRaster): ...@@ -93,7 +100,7 @@ class BsqRaster(BandRaster):
blocksize = self.nrows * rowsize blocksize = self.nrows * rowsize
bandstartpos = [] bandstartpos = []
for j in range(self.nbands): for j in range(self.nbands):
bandstartpos.append(j * blocksize) bandstartpos.append(j * blocksize)
if not HAS_NUMPY: if not HAS_NUMPY:
# The following is for the case without numpy: each line should be # The following is for the case without numpy: each line should be
......
import os.path; import os.path;
import stat
from array import array
from .const import Const, constants as const from .const import Const, constants as const
from .raster import Raster from .raster import Raster
from .gridenvelope2d import GridEnvelope2D; from .gridenvelope2d import GridEnvelope2D;
...@@ -6,7 +8,7 @@ from .gridenvelope2d import GridEnvelope2D; ...@@ -6,7 +8,7 @@ from .gridenvelope2d import GridEnvelope2D;
__author__ = "Steven B. Hoek" __author__ = "Steven B. Hoek"
class FloatingPointRaster(Raster, GridEnvelope2D): class FloatingPointRaster(Raster, GridEnvelope2D):
"A raster represented by 2 files, with extensions 'flt' and 'hdr'" """A raster represented by 2 files, with extensions 'flt' and 'hdr'"""
# Attributes - assign some dummy values for the mean time # Attributes - assign some dummy values for the mean time
_const = None _const = None
...@@ -23,7 +25,11 @@ class FloatingPointRaster(Raster, GridEnvelope2D): ...@@ -23,7 +25,11 @@ class FloatingPointRaster(Raster, GridEnvelope2D):
currow = 0; currow = 0;
__envelope = None; __envelope = None;
def __init__(self, filepath, *datatype): def __init__(self, filepath='', *datatype):
# Check input
if filepath == '':
print('File path cannot be an empty string (method __init__).')
# Initialise # Initialise
Raster.__init__(self, filepath) Raster.__init__(self, filepath)
self._const = Const() self._const = Const()
...@@ -32,6 +38,7 @@ class FloatingPointRaster(Raster, GridEnvelope2D): ...@@ -32,6 +38,7 @@ class FloatingPointRaster(Raster, GridEnvelope2D):
self._const.LSBFIRST = "LSBFIRST"; self._const.LSBFIRST = "LSBFIRST";
self._const.BYTESPERCELL = 4; self._const.BYTESPERCELL = 4;
self._const.DATAFILEXT = "flt" self._const.DATAFILEXT = "flt"
self._const.DATAFILEXTALT = "int"
self._const.WORLDEXT = "wld" self._const.WORLDEXT = "wld"
self.byteorder = self._const.LSBFIRST self.byteorder = self._const.LSBFIRST
...@@ -52,7 +59,7 @@ class FloatingPointRaster(Raster, GridEnvelope2D): ...@@ -52,7 +59,7 @@ class FloatingPointRaster(Raster, GridEnvelope2D):
# If file does not exist and mode[0] = 'w', create it! # If file does not exist and mode[0] = 'w', create it!
if (mode[0] == 'w') and (not os.path.exists(self.folder + os.path.sep + self.name)): if (mode[0] == 'w') and (not os.path.exists(self.folder + os.path.sep + self.name)):
self.datafile = open(self.folder + os.path.sep + self.name, 'w'); self.datafile = open(self.folder + os.path.sep + self.name, 'wb');
self.__envelope = GridEnvelope2D.__init__(self, ncols, nrows, xll, yll, cellsize, cellsize); self.__envelope = GridEnvelope2D.__init__(self, ncols, nrows, xll, yll, cellsize, cellsize);
return True; return True;
else: else:
...@@ -78,11 +85,17 @@ class FloatingPointRaster(Raster, GridEnvelope2D): ...@@ -78,11 +85,17 @@ class FloatingPointRaster(Raster, GridEnvelope2D):
def readheader(self): def readheader(self):
# Read header file and assign all attributes # Read header file and assign all attributes
pos = str.rfind(str(self.name), "." + self._const.DATAFILEXT); pos1 = str.rfind(str(self.name), "." + self._const.DATAFILEXT)
pos2 = str.rfind(str(self.name), "." + self._const.DATAFILEXTALT)
pos = max(pos1, pos2)
if pos != -1: hdrFilename = self.name[0:pos] + "." + const.HEADEREXT if pos != -1: hdrFilename = self.name[0:pos] + "." + const.HEADEREXT
else: raise ValueError("Invalid file name: " + self.name); else: raise ValueError("Invalid file name: " + self.name);
if os.path.exists(self.folder + os.path.sep + hdrFilename): if os.path.exists(self.folder + os.path.sep + hdrFilename):
fileinfo = os.stat(os.path.join(self.folder, self.name))
filesize = fileinfo[stat.ST_SIZE]
if filesize == 0:
raise RuntimeError("Empty header file found!")
hf = open(self.folder + os.path.sep + hdrFilename, 'r'); hf = open(self.folder + os.path.sep + hdrFilename, 'r');
hl = hf.readline(); hl = hf.readline();
self.ncols = int(hl.replace('ncols', '').strip()); self.ncols = int(hl.replace('ncols', '').strip());
...@@ -111,7 +124,8 @@ class FloatingPointRaster(Raster, GridEnvelope2D): ...@@ -111,7 +124,8 @@ class FloatingPointRaster(Raster, GridEnvelope2D):
try: try:
self.currow += 1; self.currow += 1;
if (self.currow > self.nrows): raise StopIteration; if (self.currow > self.nrows): raise StopIteration;
return self.datafile.read(self.ncols * self._const.BYTESPERCELL); result = self.datafile.read(self.ncols * self._const.BYTESPERCELL);
return array(self.datatype, result);
except: except:
raise StopIteration; raise StopIteration;
...@@ -129,7 +143,9 @@ class FloatingPointRaster(Raster, GridEnvelope2D): ...@@ -129,7 +143,9 @@ class FloatingPointRaster(Raster, GridEnvelope2D):
def writeheader(self): def writeheader(self):
# Write header file with all attributes # Write header file with all attributes
pos = str.rfind(str(self.name), "." + self._const.DATAFILEXT); pos1 = str.rfind(str(self.name), "." + self._const.DATAFILEXT)
pos2 = str.rfind(str(self.name), "." + self._const.DATAFILEXTALT)
pos = max(pos1, pos2)
if pos != -1: hdrFilename = self.name[0:pos] + "." + const.HEADEREXT if pos != -1: hdrFilename = self.name[0:pos] + "." + const.HEADEREXT
else: raise ValueError("Invalid file name: " + self.name); else: raise ValueError("Invalid file name: " + self.name);
try: try:
......
import tests
tests.test_all()
\ No newline at end of file
import unittest
from . import test_asciigrid
from . import test_floatingpointraster
from . import test_bilraster
from . import test_bsqraster
def make_test_suite(dsn=None):
"""Assemble test suite and return it
"""
allsuites = unittest.TestSuite([test_asciigrid.suite(),
test_floatingpointraster.suite(),
test_bilraster.suite(),
test_bsqraster.suite()
])
return allsuites
def test_all():
"""Assemble test suite and run the test using the TextTestRunner
"""
allsuites = make_test_suite()
unittest.TextTestRunner(verbosity=2).run(allsuites)
import unittest
from .test_asciigrid import suite as test_asciigrid_suite
def make_test_suite(dsn=None):
"""Assemble test suite and return it
"""
allsuites = unittest.TestSuite([test_asciigrid_suite()
])
return allsuites
def test_all():
"""Assemble test suite and run the test using the TextTestRunner
"""
allsuites = make_test_suite()
unittest.TextTestRunner(verbosity=2).run(allsuites)
test_all()
\ No newline at end of file
...@@ -3,4 +3,4 @@ nrows 30 ...@@ -3,4 +3,4 @@ nrows 30
xllcorner 3.25 xllcorner 3.25
yllcorner 50.625 yllcorner 50.625
cellsize 0.1 cellsize 0.1
NODATA_value -1 NODATA_value -1.0
No preview for this file type
...@@ -40,7 +40,11 @@ def main(): ...@@ -40,7 +40,11 @@ def main():
ncols = page.tags['ImageWidth'].value ncols = page.tags['ImageWidth'].value
# Also derive the data from the TIFF file; divide by 10 to get some decimals! # Also derive the data from the TIFF file; divide by 10 to get some decimals!
# And add some extra noise to make sure not all numbers in a line are the same
data = imread(fn) / 10 data = imread(fn) / 10
for i in range(nrows):
for k in range(ncols):
data[i,k] = data[i,k] + k*0.005
# Derive the geographic origin and pixel size from the world file (manipulated) # Derive the geographic origin and pixel size from the world file (manipulated)
fn = os.path.join('..', '..', 'geodata', 'float.wld') fn = os.path.join('..', '..', 'geodata', 'float.wld')
......
from formats.asciigrid import AsciiGrid from formats.asciigrid import AsciiGrid
import numpy as np from .test_baseraster import TestBaseRaster
import os.path import unittest
__author__ = "Steven B. Hoek"
class TestAsciiGrid(TestBaseRaster):
# Load data from a pickle file and metadata from a header file
# Write the data to an AsciiGrid. Close and open teh file again for reading and check
test_class = AsciiGrid
int_extension = 'asc'
flt_extension = 'asc'
def suite():
""" This defines all the tests of a module"""
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestAsciiGrid))
return suite
f = None
try:
# Test writing and reading of a grid with integer numbers
fn = os.path.join('data', 'intasc.npy')
data = np.load(fn)
hfn = os.path.join('data', 'intasc.hdr')
f = open(hfn, 'r')
header = f.readlines()
finally:
if f != None: f.close()
f = None
try:
# Test reading and writing of a grid with float numbers
fn = os.path.join('data', 'fltasc.npy')
data = np.load(fn)
finally:
if f != None: f.close()
\ No newline at end of file
import os.path
import unittest
import numpy as np
__author__ = "Steven B. Hoek"
class TestBaseRaster(unittest.TestCase):
test_class = None
int_extension = 'xxx'
flt_extension = 'xxx'
def test_int_grid(self):
f = None
br = None
curdir = os.path.dirname(__file__)
try:
# Test writing and reading of a grid with integer numbers; first the data
fn = os.path.join(curdir, 'data', 'intasc.npy')
data = np.load(fn)
# Then the header
hfn = os.path.join(curdir, 'data', 'intasc.hdr')
f = open(hfn, 'r')
hls = f.readlines()
ncols = int(hls[0].replace('ncols', ''));
nrows = int(hls[1].replace('nrows', ''));
xll = float(hls[2].replace('xllcorner', ''));
yll = float(hls[3].replace('yllcorner', ''));
cellsize = float(hls[4].replace('cellsize', ''));
nodatavalue = int(hls[5].replace('NODATA_value', ''));
# Write the file
br = self.test_class(os.path.join(curdir, 'output', 'int.' + self.int_extension), 'i')
br.open('w', ncols=ncols, nrows=nrows, xll=xll, yll=yll, cellsize=cellsize, nodatavalue=nodatavalue)
for i in range(nrows):
line = data[i, :]
br.writenext(line)
finally:
if f != None: f.close()
if br != None: br.close()
br = None
try:
# Open file for reading again
br = self.test_class(os.path.join(curdir, 'output', 'int.' + self.int_extension), 'i')
br.open('r')
self.assertEqual(nrows, br.nrows)
self.assertEqual(ncols, br.ncols)
self.assertEqual(xll, br.xll)
self.assertEqual(yll, br.yll)
self.assertEqual(cellsize, br.cellsize)
self.assertEqual(nodatavalue, br.nodatavalue)
for i in range(nrows):
line = br.next()
for k in range(ncols):
self.assertEqual(data[i,k], line[k])
finally:
if br != None: br.close()
def test_flt_grid(self):
f = None
br = None
curdir = os.path.dirname(__file__)
try:
# Test reading and writing of a grid with float numbers; first the data
fn = os.path.join(curdir, 'data', 'fltasc.npy')
data = np.load(fn)
# Then the header
hfn = os.path.join(curdir, 'data', 'fltasc.hdr')
f = open(hfn, 'r')
hls = f.readlines()
ncols = int(hls[0].replace('ncols', ''));
nrows = int(hls[1].replace('nrows', ''));
xll = float(hls[2].replace('xllcorner', ''));
yll = float(hls[3].replace('yllcorner', ''));
cellsize = float(hls[4].replace('cellsize', ''));
nodatavalue = float(hls[5].replace('NODATA_value', ''));
# Write the file
br = self.test_class(os.path.join(curdir, 'output', 'flt.' + self.flt_extension), 'f')
br.open('w', ncols=ncols, nrows=nrows, xll=xll, yll=yll, cellsize=cellsize, nodatavalue=nodatavalue)
for i in range(nrows):
line = data[i, :]
br.writenext(line)
finally:
if f != None: f.close()
if br != None: br.close()
try:
# Open file for reading again
fname = os.path.join(curdir, 'output', 'flt.' + self.flt_extension)
br = self.test_class(fname, 'f')
br.open('r')
self.assertEqual(nrows, br.nrows)
self.assertEqual(ncols, br.ncols)
self.assertAlmostEqual(xll, br.xll, places=3)
self.assertAlmostEqual(yll, br.yll, places=3)
self.assertAlmostEqual(cellsize, br.cellsize, places=3)
self.assertAlmostEqual(nodatavalue, br.nodatavalue, places=3)
for i in range(nrows):
line = br.next()
for k in range(ncols):
self.assertAlmostEqual(data[i,k], line[k], places=3)
finally:
if br != None: br.close()
\ No newline at end of file
from formats.bilraster import BilRaster from formats.bilraster import BilRaster
from .test_baseraster import TestBaseRaster
import unittest
# Test reading and writing of a grid with integer numbers __author__ = "Steven B. Hoek"
# Test reading and writing of a grid with float numbers # TODO this test has limited relevance because the test is carried out with only one band (= default)
\ No newline at end of file
class TestBilRaster(TestBaseRaster):
# Load data from a pickle file and metadata from a header file
# Write the data to an AsciiGrid. Close and open teh file again for reading and check
test_class = BilRaster
int_extension = 'bil'
flt_extension = 'bil'
def suite():
""" This defines all the tests of a module"""
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestBilRaster))
return suite
\ No newline at end of file
from formats.bsqraster import BsqRaster
from .test_baseraster import TestBaseRaster
import unittest
__author__ = "Steven B. Hoek"
# TODO this test has limited relevance because the test is carried out with only one band (= default)