Index: src/sas/sascalc/dataloader/file_reader_base_class.py
===================================================================
--- src/sas/sascalc/dataloader/file_reader_base_class.py	(revision beba407166875d49f41ca9bd2cf10087b2575153)
+++ src/sas/sascalc/dataloader/file_reader_base_class.py	(revision b09095a7f7ba6ae5e7ee28a9d240400222cbae19)
@@ -1,4 +1,4 @@
 """
-This is the base file reader class all file readers should inherit from.
+This is the base file reader class most file readers should inherit from.
 All generic functionality required for a file loader/reader is built into this
 class
@@ -7,4 +7,5 @@
 import os
 import logging
+import numpy as np
 from abc import abstractmethod
 from loader_exceptions import NoKnownLoaderException, FileContentsException,\
@@ -19,14 +20,22 @@
     # List of Data1D and Data2D objects to be sent back to data_loader
     output = []
-    # Current plottable1D/2D object being loaded in
+    # Current plottable_(1D/2D) object being loaded in
     current_dataset = None
-    # Current DataInfo objecct being loaded in
+    # Current DataInfo object being loaded in
     current_datainfo = None
-    # Wildcards
-    type = ["Text files (*.txt)"]
+    # String to describe the type of data this reader can load
+    type_name = "ASCII"
+    # Wildcards to display
+    type = ["Text files (*.txt|*.TXT)"]
     # List of allowed extensions
     ext = ['.txt']
     # Bypass extension check and try to load anyway
     allow_all = False
+    # Able to import the unit converter
+    has_converter = True
+    # Open file handle
+    f_open = None
+    # Default value of zero
+    _ZERO = 1e-16
 
     def read(self, filepath):
@@ -42,19 +51,29 @@
                 # Try to load the file, but raise an error if unable to.
                 try:
-                    input_f = open(filepath, 'rb')
-                    self.get_file_contents(input_f)
+                    self.unit_converter()
+                    self.f_open = open(filepath, 'rb')
+                    self.get_file_contents()
+                    self.sort_one_d_data()
                 except RuntimeError:
+                    # Reader specific errors
+                    # TODO: Give a specific error.
                     pass
                 except OSError as e:
+                    # If the file cannot be opened
                     msg = "Unable to open file: {}\n".format(filepath)
                     msg += e.message
                     self.handle_error_message(msg)
                 except Exception as e:
-                    self.handle_error_message(e.message)
+                    # Handle any other generic error
+                    # TODO: raise or log?
+                    raise
+                finally:
+                    if not self.f_open.closed:
+                        self.f_open.close()
         else:
             msg = "Unable to find file at: {}\n".format(filepath)
             msg += "Please check your file path and try again."
             self.handle_error_message(msg)
-        # Return a list of parsed entries that dataloader can manage
+        # Return a list of parsed entries that data_loader can manage
         return self.output
 
@@ -79,9 +98,61 @@
         self.output.append(data_obj)
 
+    def unit_converter(self):
+        """
+        Generic unit conversion import 
+        """
+        # Check whether we have a converter available
+        self.has_converter = True
+        try:
+            from sas.sascalc.data_util.nxsunit import Converter
+        except:
+            self.has_converter = False
+
+    def sort_one_d_data(self):
+        """
+        Sort 1D data along the X axis for consistency
+        """
+        final_list = []
+        for data in self.output:
+            if isinstance(data, Data1D):
+                ind = np.lexsort((data.y, data.x))
+                data.x = np.asarray([data.x[i] for i in ind])
+                data.y = np.asarray([data.y[i] for i in ind])
+                if data.dx is not None:
+                    data.dx = np.asarray([data.dx[i] for i in ind])
+                if data.dxl is not None:
+                    data.dxl = np.asarray([data.dxl[i] for i in ind])
+                if data.dxw is not None:
+                    data.dxw = np.asarray([data.dxw[i] for i in ind])
+                if data.dy is not None:
+                    data.dy = np.asarray([data.dy[i] for i in ind])
+                if data.lam is not None:
+                    data.lam = np.asarray([data.lam[i] for i in ind])
+                if data.dlam is not None:
+                    data.dlam = np.asarray([data.dlam[i] for i in ind])
+            final_list.append(data)
+        self.output = final_list
+
+    @staticmethod
+    def splitline(line):
+        """
+        Splits a line into pieces based on common delimeters
+        :param line: A single line of text
+        :return: list of values
+        """
+        # Initial try for CSV (split on ,)
+        toks = line.split(',')
+        # Now try SCSV (split on ;)
+        if len(toks) < 2:
+            toks = line.split(';')
+        # Now go for whitespace
+        if len(toks) < 2:
+            toks = line.split()
+        return toks
+
     @abstractmethod
-    def get_file_contents(self, contents):
+    def get_file_contents(self):
         """
-        All reader classes that inherit from here should implement
-        :param contents: 
+        All reader classes that inherit from FileReader must implement
         """
         pass
Index: src/sas/sascalc/dataloader/readers/ascii_reader.py
===================================================================
--- src/sas/sascalc/dataloader/readers/ascii_reader.py	(revision 235f514ba93b57fa63e44309f182acef0b98bb55)
+++ src/sas/sascalc/dataloader/readers/ascii_reader.py	(revision b09095a7f7ba6ae5e7ee28a9d240400222cbae19)
@@ -1,245 +1,175 @@
 """
-    ASCII reader
+    Generic multi-column ASCII data reader
 """
 ############################################################################
-#This software was developed by the University of Tennessee as part of the
-#Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
-#project funded by the US National Science Foundation. 
-#If you use DANSE applications to do scientific research that leads to
-#publication, we ask that you acknowledge the use of the software with the
-#following sentence:
-#This work benefited from DANSE software developed under NSF award DMR-0520547.
-#copyright 2008, University of Tennessee
+# This software was developed by the University of Tennessee as part of the
+# Distributed Data Analysis of Neutron Scattering Experiments (DANSE)
+# project funded by the US National Science Foundation.
+# If you use DANSE applications to do scientific research that leads to
+# publication, we ask that you acknowledge the use of the software with the
+# following sentence:
+# This work benefited from DANSE software developed under NSF award DMR-0520547.
+# copyright 2008, University of Tennessee
 #############################################################################
 
+import logging
+import numpy as np
+from sas.sascalc.dataloader.file_reader_base_class import FileReader
+from sas.sascalc.dataloader.data_info import DataInfo, plottable_1D
 
-import numpy as np
-import os
-from sas.sascalc.dataloader.data_info import Data1D
-
-# Check whether we have a converter available
-has_converter = True
-try:
-    from sas.sascalc.data_util.nxsunit import Converter
-except:
-    has_converter = False
-_ZERO = 1e-16
+logger = logging.getLogger(__name__)
 
 
-class Reader:
+class Reader(FileReader):
     """
     Class to load ascii files (2, 3 or 4 columns).
     """
-    ## File type
+    # File type
     type_name = "ASCII"
-
-    ## Wildcards
+    # Wildcards
     type = ["ASCII files (*.txt)|*.txt",
             "ASCII files (*.dat)|*.dat",
             "ASCII files (*.abs)|*.abs",
             "CSV files (*.csv)|*.csv"]
-    ## List of allowed extensions
-    ext = ['.txt', '.TXT', '.dat', '.DAT', '.abs', '.ABS', 'csv', 'CSV']
+    # List of allowed extensions
+    ext = ['.txt', '.dat', '.abs', '.csv']
+    # Flag to bypass extension check
+    allow_all = True
+    # data unless that is the only data
+    min_data_pts = 5
 
-    ## Flag to bypass extension check
-    allow_all = True
+    def get_file_contents(self):
+        """
+        Get the contents of the file
+        """
 
-    def read(self, path):
-        """
-        Load data file
+        buff = self.f_open.read()
+        filepath = self.f_open.name
+        lines = buff.splitlines()
+        self.output = []
+        self.current_datainfo = DataInfo()
+        self.current_datainfo.filename = filepath
+        self.reset_data_list(len(lines))
 
-        :param path: file path
-        :return: Data1D object, or None
+        # The first good line of data will define whether
+        # we have 2-column or 3-column ascii
+        has_error_dx = None
+        has_error_dy = None
 
-        :raise RuntimeError: when the file can't be opened
-        :raise ValueError: when the length of the data vectors are inconsistent
-        """
-        if os.path.isfile(path):
-            basename = os.path.basename(path)
-            _, extension = os.path.splitext(basename)
-            if self.allow_all or extension.lower() in self.ext:
-                try:
-                    # Read in binary mode since GRASP frequently has no-ascii
-                    # characters that breaks the open operation
-                    input_f = open(path,'rb')
-                except:
-                    raise  RuntimeError, "ascii_reader: cannot open %s" % path
-                buff = input_f.read()
-                lines = buff.splitlines()
+        # Initialize counters for data lines and header lines.
+        is_data = False
+        # More than "5" lines of data is considered as actual
+        # To count # of current data candidate lines
+        candidate_lines = 0
+        # To count total # of previous data candidate lines
+        candidate_lines_previous = 0
+        # Current line number
+        line_no = 0
+        # minimum required number of columns of data
+        lentoks = 2
+        for line in lines:
+            toks = self.splitline(line.strip())
+            # To remember the number of columns in the current line of data
+            new_lentoks = len(toks)
+            try:
+                if new_lentoks == 0:
+                    # If the line is blank, skip and continue on
+                    # In case of breaks within data sets.
+                    continue
+                elif new_lentoks != lentoks and is_data:
+                    # If a footer is found, break the loop and save the data
+                    break
+                elif new_lentoks != lentoks and not is_data:
+                    # If header lines are numerical
+                    candidate_lines = 0
+                    self.reset_data_list(len(lines) - line_no)
 
-                # Arrays for data storage
-                tx = np.zeros(0)
-                ty = np.zeros(0)
-                tdy = np.zeros(0)
-                tdx = np.zeros(0)
+                candidate_lines += 1
+                # If 5 or more lines, this is considering the set data
+                if candidate_lines >= self.min_data_pts:
+                    is_data = True
 
-                # The first good line of data will define whether
-                # we have 2-column or 3-column ascii
+                self.current_dataset.x[candidate_lines - 1] = float(toks[0])
+                self.current_dataset.y[candidate_lines - 1] = float(toks[1])
+
+                # If a 3rd row is present, consider it dy
+                if new_lentoks > 2:
+                    self.current_dataset.dy[candidate_lines - 1] = \
+                        float(toks[2])
+                    has_error_dy = True
+
+                # If a 4th row is present, consider it dx
+                if new_lentoks > 3:
+                    self.current_dataset.dx[candidate_lines - 1] = \
+                        float(toks[3])
+                    has_error_dx = True
+
+                # To remember the # of columns on the current line
+                # for the next line of data
+                lentoks = new_lentoks
+                line_no += 1
+            except ValueError:
+                # It is data and meet non - number, then stop reading
+                if is_data:
+                    break
+                # Delete the previously stored lines of data candidates if
+                # the list is not data
+                self.reset_data_list(len(lines) - line_no)
+                lentoks = 2
                 has_error_dx = None
                 has_error_dy = None
+                # Reset # of lines of data candidates
+                candidate_lines = 0
+            except Exception:
+                # Handle any unexpected exceptions
+                raise
 
-                #Initialize counters for data lines and header lines.
-                is_data = False
-                # More than "5" lines of data is considered as actual
-                # data unless that is the only data
-                min_data_pts = 5
-                # To count # of current data candidate lines
-                candidate_lines = 0
-                # To count total # of previous data candidate lines
-                candidate_lines_previous = 0
-                #minimum required number of columns of data
-                lentoks = 2
-                for line in lines:
-                    toks = self.splitline(line)
-                    # To remember the # of columns in the current line of data
-                    new_lentoks = len(toks)
-                    try:
-                        if new_lentoks == 1 and not is_data:
-                            ## If only one item in list, no longer data
-                            raise ValueError
-                        elif new_lentoks == 0:
-                            ## If the line is blank, skip and continue on
-                            ## In case of breaks within data sets.
-                            continue
-                        elif new_lentoks != lentoks and is_data:
-                            ## If a footer is found, break the loop and save the data
-                            break
-                        elif new_lentoks != lentoks and not is_data:
-                            ## If header lines are numerical
-                            candidate_lines = 0
-                            candidate_lines_previous = 0
+        if not is_data:
+            # TODO: Check file extension - primary reader, throw error.
+            # TODO: Secondary check, pass and try next reader
+            msg = "ascii_reader: x has no data"
+            raise RuntimeError(msg)
+        # Sanity check
+        if has_error_dy and not len(self.current_dataset.y) == \
+                len(self.current_dataset.dy):
+            msg = "ascii_reader: y and dy have different length"
+            raise RuntimeError(msg)
+        if has_error_dx and not len(self.current_dataset.x) == \
+                len(self.current_dataset.dx):
+            msg = "ascii_reader: y and dy have different length"
+            raise RuntimeError(msg)
+        # If the data length is zero, consider this as
+        # though we were not able to read the file.
+        if len(self.current_dataset.x) < 1:
+            raise RuntimeError("ascii_reader: could not load file")
+            return None
 
-                        #Make sure that all columns are numbers.
-                        for colnum in range(len(toks)):
-                            # Any non-floating point values throw ValueError
-                            float(toks[colnum])
+        # Data
+        self.current_dataset.x = \
+            self.current_dataset.x[self.current_dataset.x != 0]
+        self.current_dataset.y = \
+            self.current_dataset.y[self.current_dataset.x != 0]
+        self.current_dataset.dy = \
+            self.current_dataset.dy[self.current_dataset.x != 0] if \
+                has_error_dy else np.zeros(len(self.current_dataset.y))
+        self.current_dataset.dx = \
+            self.current_dataset.dx[self.current_dataset.x != 0] if \
+                has_error_dx else np.zeros(len(self.current_dataset.x))
 
-                        candidate_lines += 1
-                        _x = float(toks[0])
-                        _y = float(toks[1])
-                        _dx = None
-                        _dy = None
+        self.current_dataset.xaxis("\\rm{Q}", 'A^{-1}')
+        self.current_dataset.yaxis("\\rm{Intensity}", "cm^{-1}")
 
-                        #If 5 or more lines, this is considering the set data
-                        if candidate_lines >= min_data_pts:
-                            is_data = True
+        # Store loading process information
+        self.current_datainfo.meta_data['loader'] = self.type_name
+        self.send_to_output()
 
-                        # If a 3rd row is present, consider it dy
-                        if new_lentoks > 2:
-                            _dy = float(toks[2])
-                        has_error_dy = False if _dy is None else True
-
-                        # If a 4th row is present, consider it dx
-                        if new_lentoks > 3:
-                            _dx = float(toks[3])
-                        has_error_dx = False if _dx is None else True
-
-                        # Delete the previously stored lines of data candidates if
-                        # the list is not data
-                        if candidate_lines == 1 and -1 < candidate_lines_previous < min_data_pts and \
-                            is_data == False:
-                            try:
-                                tx = np.zeros(0)
-                                ty = np.zeros(0)
-                                tdy = np.zeros(0)
-                                tdx = np.zeros(0)
-                            except:
-                                pass
-
-                        if has_error_dy == True:
-                            tdy = np.append(tdy, _dy)
-                        if has_error_dx == True:
-                            tdx = np.append(tdx, _dx)
-                        tx = np.append(tx, _x)
-                        ty = np.append(ty, _y)
-
-                        #To remember the # of columns on the current line
-                        # for the next line of data
-                        lentoks = new_lentoks
-                        candidate_lines_previous = candidate_lines
-                    except ValueError:
-                        # It is data and meet non - number, then stop reading
-                        if is_data == True:
-                            break
-                        lentoks = 2
-                        has_error_dx = None
-                        has_error_dy = None
-                        #Reset # of lines of data candidates
-                        candidate_lines = 0
-                    except:
-                        pass
-
-                input_f.close()
-                if not is_data:
-                    msg = "ascii_reader: x has no data"
-                    raise RuntimeError, msg
-                # Sanity check
-                if has_error_dy == True and not len(ty) == len(tdy):
-                    msg = "ascii_reader: y and dy have different length"
-                    raise RuntimeError, msg
-                if has_error_dx == True and not len(tx) == len(tdx):
-                    msg = "ascii_reader: y and dy have different length"
-                    raise RuntimeError, msg
-                # If the data length is zero, consider this as
-                # though we were not able to read the file.
-                if len(tx) == 0:
-                    raise RuntimeError, "ascii_reader: could not load file"
-
-                #Let's re-order the data to make cal.
-                # curve look better some cases
-                ind = np.lexsort((ty, tx))
-                x = np.zeros(len(tx))
-                y = np.zeros(len(ty))
-                dy = np.zeros(len(tdy))
-                dx = np.zeros(len(tdx))
-                output = Data1D(x, y, dy=dy, dx=dx)
-                self.filename = output.filename = basename
-
-                for i in ind:
-                    x[i] = tx[ind[i]]
-                    y[i] = ty[ind[i]]
-                    if has_error_dy == True:
-                        dy[i] = tdy[ind[i]]
-                    if has_error_dx == True:
-                        dx[i] = tdx[ind[i]]
-                # Zeros in dx, dy
-                if has_error_dx:
-                    dx[dx == 0] = _ZERO
-                if has_error_dy:
-                    dy[dy == 0] = _ZERO
-                #Data
-                output.x = x[x != 0]
-                output.y = y[x != 0]
-                output.dy = dy[x != 0] if has_error_dy == True\
-                    else np.zeros(len(output.y))
-                output.dx = dx[x != 0] if has_error_dx == True\
-                    else np.zeros(len(output.x))
-
-                output.xaxis("\\rm{Q}", 'A^{-1}')
-                output.yaxis("\\rm{Intensity}", "cm^{-1}")
-
-                # Store loading process information
-                output.meta_data['loader'] = self.type_name
-                if len(output.x) < 1:
-                    raise RuntimeError, "%s is empty" % path
-                return output
-
-        else:
-            raise RuntimeError, "%s is not a file" % path
-        return None
-
-    def splitline(self, line):
+    def reset_data_list(self, no_lines):
         """
-        Splits a line into pieces based on common delimeters
-        :param line: A single line of text
-        :return: list of values
+        Reset the plottable_1D object
         """
-        # Initial try for CSV (split on ,)
-        toks = line.split(',')
-        # Now try SCSV (split on ;)
-        if len(toks) < 2:
-            toks = line.split(';')
-        # Now go for whitespace
-        if len(toks) < 2:
-            toks = line.split()
-        return toks
+        # Initialize data sets with arrays the maximum possible size
+        x = np.zeros(no_lines)
+        y = np.zeros(no_lines)
+        dy = np.zeros(no_lines)
+        dx = np.zeros(no_lines)
+        self.current_dataset = plottable_1D(x, y, dx, dy)
Index: test/sascalculator/test/utest_slit_length_calculator.py
===================================================================
--- test/sascalculator/test/utest_slit_length_calculator.py	(revision 959eb0181ad06828a748f04512f953aad5b31659)
+++ test/sascalculator/test/utest_slit_length_calculator.py	(revision b09095a7f7ba6ae5e7ee28a9d240400222cbae19)
@@ -5,9 +5,9 @@
 import unittest
 from sas.sascalc.dataloader.readers.ascii_reader import Reader
-from  sas.sascalc.calculator.slit_length_calculator import SlitlengthCalculator as calculator
+from sas.sascalc.calculator.slit_length_calculator import SlitlengthCalculator \
+    as calculator
 
-import os.path
 
-class slit_calculator(unittest.TestCase):
+class SlitCalculator(unittest.TestCase):
     
     def setUp(self):
@@ -15,16 +15,18 @@
         self.reader = Reader()
         
-    def test_slitlength_calculation(self):
+    def test_slit_length_calculation(self):
         """
             Test slit_length_calculator"
         """
-        f = self.reader.read("beam profile.DAT")
+        list = self.reader.read("beam profile.DAT")
+        self.assertTrue(len(list) == 1)
+        f = list[0]
         cal = calculator()
         cal.set_data(f.x,f.y)
-        slitlength = cal.calculate_slit_length()
+        slit_length = cal.calculate_slit_length()
         
         # The value "5.5858" was obtained by manual calculation.
         # It turns out our slit length is FWHM/2
-        self.assertAlmostEqual(slitlength,5.5858/2, 3)
+        self.assertAlmostEqual(slit_length, 5.5858/2, 3)
         
         
Index: test/sasdataloader/test/utest_ascii.py
===================================================================
--- test/sasdataloader/test/utest_ascii.py	(revision 959eb0181ad06828a748f04512f953aad5b31659)
+++ test/sasdataloader/test/utest_ascii.py	(revision b09095a7f7ba6ae5e7ee28a9d240400222cbae19)
@@ -6,12 +6,21 @@
 
 import unittest
-from sas.sascalc.dataloader.loader import  Loader
- 
-import os.path
+from sas.sascalc.dataloader.loader import Loader
 
-class abs_reader(unittest.TestCase):
+
+class ABSReaderTests(unittest.TestCase):
     
     def setUp(self):
         self.loader = Loader()
+        self.f1_list = self.loader.load("ascii_test_1.txt")
+        self.f1 = self.f1_list[0]
+        self.f2_list = self.loader.load("ascii_test_2.txt")
+        self.f2 = self.f2_list[0]
+        self.f3_list = self.loader.load("ascii_test_3.txt")
+        self.f3 = self.f3_list[0]
+        self.f4_list = self.loader.load("ascii_test_4.abs")
+        self.f4 = self.f4_list[0]
+        self.f5_list = self.loader.load("ascii_test_5.txt")
+        self.f5 = self.f5_list[0]
         
     def test_checkdata(self):
@@ -19,13 +28,12 @@
             Test .ABS file loaded as ascii
         """
-        f = self.loader.load("ascii_test_1.txt")
         # The length of the data is 10
-        self.assertEqual(len(f.x), 10)
-        self.assertEqual(f.x[0],0.002618)
-        self.assertEqual(f.x[9],0.0497)
-        self.assertEqual(f.x_unit, '1/A')
-        self.assertEqual(f.y_unit, '1/cm')
+        self.assertEqual(len(self.f1.x), 10)
+        self.assertEqual(self.f1.x[0],0.002618)
+        self.assertEqual(self.f1.x[9],0.0497)
+        self.assertEqual(self.f1.x_unit, '1/A')
+        self.assertEqual(self.f1.y_unit, '1/cm')
         
-        self.assertEqual(f.meta_data['loader'],"ASCII")
+        self.assertEqual(self.f1.meta_data['loader'],"ASCII")
         
     def test_truncated_1(self):
@@ -38,10 +46,8 @@
             as though it were the start of a footer).
         """
-        # Test .ABS file loaded as ascii
-        f = self.loader.load("ascii_test_2.txt")
-        # The length of the data is 10
-        self.assertEqual(len(f.x), 5)
-        self.assertEqual(f.x[0],0.002618)
-        self.assertEqual(f.x[4],0.02356)
+        # The length of the data is 5
+        self.assertEqual(len(self.f2.x), 5)
+        self.assertEqual(self.f2.x[0],0.002618)
+        self.assertEqual(self.f2.x[4],0.02356)
         
     def test_truncated_2(self):
@@ -52,10 +58,8 @@
             reading at the first inconsitent line.
         """
-        # Test .ABS file loaded as ascii
-        f = self.loader.load("ascii_test_3.txt")
         # The length of the data is 5
-        self.assertEqual(len(f.x), 5)
-        self.assertEqual(f.x[0],0.002618)
-        self.assertEqual(f.x[4],0.02356)
+        self.assertEqual(len(self.f3.x), 5)
+        self.assertEqual(self.f3.x[0],0.002618)
+        self.assertEqual(self.f3.x[4],0.02356)
         
     def test_truncated_3(self):
@@ -66,10 +70,8 @@
             reading at the last line of header.
         """
-        # Test .ABS file loaded as ascii
-        f = self.loader.load("ascii_test_4.abs")
         # The length of the data is 5
-        self.assertEqual(len(f.x), 5)
-        self.assertEqual(f.x[0],0.012654)
-        self.assertEqual(f.x[4],0.02654)
+        self.assertEqual(len(self.f4.x), 5)
+        self.assertEqual(self.f4.x[0],0.012654)
+        self.assertEqual(self.f4.x[4],0.02654)
         
     def test_truncated_4(self):
@@ -78,16 +80,14 @@
             Only the last 5 2-col lines should be read.
         """
-        # Test .ABS file loaded as ascii
-        f = self.loader.load("ascii_test_5.txt")
         # The length of the data is 5
-        self.assertEqual(len(f.x), 5)
-        self.assertEqual(f.x[0],0.02879)
-        self.assertEqual(f.x[4],0.0497)
+        self.assertEqual(len(self.f5.x), 5)
+        self.assertEqual(self.f5.x[0],0.02879)
+        self.assertEqual(self.f5.x[4],0.0497)
         
     def test_truncated_5(self):
         """
-            Test a 6-col ascii file with complex header where one of them has a letter and 
-            many lines with 2 or 2 columns in the middle of the data section.
-            Only last four lines should be read.
+            Test a 6-col ascii file with complex header where one of them has a
+            letter and many lines with 2 or 2 columns in the middle of the data
+            section. Will be rejected because fewer than 5 lines.
         """
         # Test .ABS file loaded as ascii
Index: test/sasdataloader/test/utest_averaging.py
===================================================================
--- test/sasdataloader/test/utest_averaging.py	(revision 9a5097cd1c76689d1f997b85ba43d12a95d8f243)
+++ test/sasdataloader/test/utest_averaging.py	(revision b09095a7f7ba6ae5e7ee28a9d240400222cbae19)
@@ -3,5 +3,5 @@
 import math
 
-from sas.sascalc.dataloader.loader import  Loader
+from sas.sascalc.dataloader.loader import Loader
 from sas.sascalc.dataloader.manipulations import Ring, CircularAverage, SectorPhi, get_q,reader2D_converter
 
@@ -110,5 +110,6 @@
         
         o = r(self.data)
-        answer = Loader().load('ring_testdata.txt')
+        data_list = Loader().load('ring_testdata.txt')
+        answer = data_list[0]
         
         for i in range(r.nbins_phi - 1):
Index: test/sasinvariant/test/utest_use_cases.py
===================================================================
--- test/sasinvariant/test/utest_use_cases.py	(revision 959eb0181ad06828a748f04512f953aad5b31659)
+++ test/sasinvariant/test/utest_use_cases.py	(revision b09095a7f7ba6ae5e7ee28a9d240400222cbae19)
@@ -6,10 +6,11 @@
 import unittest
 from sas.sascalc.dataloader.loader import  Loader
-
 from sas.sascalc.invariant import invariant
+
 
 class Data1D:
     pass
-    
+
+
 class TestLineFit(unittest.TestCase):
     """
@@ -17,15 +18,16 @@
     """
     def setUp(self):
-        self.data = Loader().load("linefittest.txt")
-        
+        self.data_list = Loader().load("linefittest.txt")
+        self.data = self.data_list[0]
+
     def test_fit_line_data(self):
         """ 
             Fit_Test_1: test linear fit, ax +b, without fixed
         """
-        
+
         # Create invariant object. Background and scale left as defaults.
         fit = invariant.Extrapolator(data=self.data)
         
-        ##Without holding
+        # Without holding
         p, dp = fit.fit(power=None)
 
@@ -33,5 +35,4 @@
         self.assertAlmostEquals(p[0], 2.3983,3)
         self.assertAlmostEquals(p[1], 0.87833,3)
-
 
     def test_fit_line_data_fixed(self):
@@ -39,9 +40,9 @@
             Fit_Test_2: test linear fit, ax +b, with 'a' fixed
         """
-        
+
         # Create invariant object. Background and scale left as defaults.
         fit = invariant.Extrapolator(data=self.data)
-        
-        #With holding a = -power =4
+
+        # With holding a = -power =4
         p, dp = fit.fit(power=-4)
 
@@ -49,5 +50,6 @@
         self.assertAlmostEquals(p[0], 4)
         self.assertAlmostEquals(p[1], -4.0676,3)
-        
+
+
 class TestLineFitNoweight(unittest.TestCase):
     """
@@ -55,15 +57,16 @@
     """
     def setUp(self):
-        self.data = Loader().load("linefittest_no_weight.txt")
-        
+        self.data_list = Loader().load("linefittest_no_weight.txt")
+        self.data = self.data_list[0]
+
     def skip_test_fit_line_data_no_weight(self):
         """ 
             Fit_Test_1: test linear fit, ax +b, without fixed
         """
-        
+
         # Create invariant object. Background and scale left as defaults.
         fit = invariant.Extrapolator(data=self.data)
-        
-        ##Without holding
+
+        # Without holding
         p, dp = fit.fit(power=None)
 
@@ -71,5 +74,4 @@
         self.assertAlmostEquals(p[0], 2.4727,3)
         self.assertAlmostEquals(p[1], 0.6,3)
-
 
     def test_fit_line_data_fixed_no_weight(self):
@@ -77,8 +79,8 @@
             Fit_Test_2: test linear fit, ax +b, with 'a' fixed
         """
-        
+
         # Create invariant object. Background and scale left as defaults.
         fit = invariant.Extrapolator(data=self.data)
-        
+
         #With holding a = -power =4
         p, dp = fit.fit(power=-4)
@@ -87,5 +89,6 @@
         self.assertAlmostEquals(p[0], 4)
         self.assertAlmostEquals(p[1], -7.8,3)
-                
+
+
 class TestInvPolySphere(unittest.TestCase):
     """
@@ -93,12 +96,11 @@
     """
     def setUp(self):
-        self.data = Loader().load("PolySpheres.txt")
-        
+        self.data_list = Loader().load("PolySpheres.txt")
+        self.data = self.data_list[0]
+
     def test_wrong_data(self):
         """ test receiving Data1D not of type loader"""
-
-
         self.assertRaises(ValueError,invariant.InvariantCalculator, Data1D())
-        
+
     def test_use_case_1(self):
         """
@@ -107,13 +109,14 @@
         # Create invariant object. Background and scale left as defaults.
         inv = invariant.InvariantCalculator(data=self.data)
-        
+
         # We have to be able to tell the InvariantCalculator whether we want the
         # extrapolation or not. By default, when the user doesn't specify, we
-        # should compute Q* without extrapolation. That's what should be done in __init__.
-        
+        # should compute Q* without extrapolation. That's what should be done
+        # in __init__.
+
         # We call get_qstar() with no argument, which signifies that we do NOT
         # want extrapolation.
         qstar = inv.get_qstar()
-        
+
         # The volume fraction and surface use Q*. That means that the following 
         # methods should check that Q* has been computed. If not, it should 
@@ -121,21 +124,21 @@
         v, dv = inv.get_volume_fraction_with_error(contrast=2.6e-6)
         s, ds = inv.get_surface_with_error(contrast=2.6e-6, porod_const=2)
-        
+
         # Test results
         self.assertAlmostEquals(qstar, 7.48959e-5,2)
         self.assertAlmostEquals(v, 0.005644689, 4)
         self.assertAlmostEquals(s , 941.7452, 3)
-        
+
     def test_use_case_2(self):
         """
-            Invariant without extrapolation. Invariant, volume fraction and surface 
-            are given with errors.
-        """
-        # Create invariant object. Background and scale left as defaults.
-        inv = invariant.InvariantCalculator(data=self.data)
-        
+        Invariant without extrapolation. Invariant, volume fraction and surface 
+        are given with errors.
+        """
+        # Create invariant object. Background and scale left as defaults.
+        inv = invariant.InvariantCalculator(data=self.data)
+
         # Get the invariant with errors
         qstar, qstar_err = inv.get_qstar_with_error()
-        
+
         # The volume fraction and surface use Q*. That means that the following 
         # methods should check that Q* has been computed. If not, it should 
@@ -147,6 +150,5 @@
         self.assertAlmostEquals(v, 0.005644689, 1)
         self.assertAlmostEquals(s , 941.7452, 3)
-       
-        
+
     def test_use_case_3(self):
         """
@@ -155,21 +157,23 @@
         # Create invariant object. Background and scale left as defaults.
         inv = invariant.InvariantCalculator(data=self.data)
-        
+
         # Set the extrapolation parameters for the low-Q range
-        
+
         # The npts parameter should have a good default.
         # The range parameter should be 'high' or 'low'
         # The function parameter should default to None. If it is None,
-        #    the method should pick a good default (Guinier at low-Q and 1/q^4 at high-Q).
-        #    The method should also check for consistency of the extrapolation and function
-        #    parameters. For instance, you might not want to allow 'high' and 'guinier'.
+        #    the method should pick a good default
+        #    (Guinier at low-Q and 1/q^4 at high-Q).
+        #    The method should also check for consistency of the extrapolation
+        #    and function parameters. For instance, you might not want to allow
+        #    'high' and 'guinier'.
         # The power parameter (not shown below) should default to 4.
         inv.set_extrapolation(range='low', npts=10, function='guinier')
-        
-        # The version of the call without error
-        # At this point, we could still compute Q* without extrapolation by calling
-        # get_qstar with arguments, or with extrapolation=None.
+
+        # The version of the call without error
+        # At this point, we could still compute Q* without extrapolation by
+        # calling get_qstar with arguments, or with extrapolation=None.
         qstar = inv.get_qstar(extrapolation='low')
-        
+
         # The version of the call with error
         qstar, qstar_err = inv.get_qstar_with_error(extrapolation='low')
@@ -178,10 +182,10 @@
         v, dv = inv.get_volume_fraction_with_error(contrast=2.6e-6)
         s, ds = inv.get_surface_with_error(contrast=2.6e-6, porod_const=2)
-        
+
         # Test results
         self.assertAlmostEquals(qstar, 7.49e-5, 1)
         self.assertAlmostEquals(v, 0.005648401, 4)
         self.assertAlmostEquals(s , 941.7452, 3)
-            
+
     def test_use_case_4(self):
         """
@@ -190,12 +194,14 @@
         # Create invariant object. Background and scale left as defaults.
         inv = invariant.InvariantCalculator(data=self.data)
+
+        # Set the extrapolation parameters for the high-Q range
+        inv.set_extrapolation(range='high', npts=10, function='power_law',
+                              power=4)
         
-        # Set the extrapolation parameters for the high-Q range
-        inv.set_extrapolation(range='high', npts=10, function='power_law', power=4)
-        
-        # The version of the call without error
-        # The function parameter defaults to None, then is picked to be 'power_law' for extrapolation='high'
+        # The version of the call without error
+        # The function parameter defaults to None, then is picked to be
+        # 'power_law' for extrapolation='high'
         qstar = inv.get_qstar(extrapolation='high')
-        
+
         # The version of the call with error
         qstar, qstar_err = inv.get_qstar_with_error(extrapolation='high')
@@ -204,10 +210,10 @@
         v, dv = inv.get_volume_fraction_with_error(contrast=2.6e-6)
         s, ds = inv.get_surface_with_error(contrast=2.6e-6, porod_const=2)
-        
+
         # Test results
         self.assertAlmostEquals(qstar, 7.49e-5,2)
         self.assertAlmostEquals(v, 0.005952674, 3)
         self.assertAlmostEquals(s , 941.7452, 3)
-        
+
     def test_use_case_5(self):
         """
@@ -216,11 +222,13 @@
         # Create invariant object. Background and scale left as defaults.
         inv = invariant.InvariantCalculator(data=self.data)
-        
+
         # Set the extrapolation parameters for the low- and high-Q ranges
         inv.set_extrapolation(range='low', npts=10, function='guinier')
-        inv.set_extrapolation(range='high', npts=10, function='power_law', power=4)
-        
-        # The version of the call without error
-        # The function parameter defaults to None, then is picked to be 'power_law' for extrapolation='high'
+        inv.set_extrapolation(range='high', npts=10, function='power_law',
+                              power=4)
+
+        # The version of the call without error
+        # The function parameter defaults to None, then is picked to be
+        # 'power_law' for extrapolation='high'
         qstar = inv.get_qstar(extrapolation='both')
         
@@ -231,10 +239,10 @@
         v, dv = inv.get_volume_fraction_with_error(contrast=2.6e-6)
         s, ds = inv.get_surface_with_error(contrast=2.6e-6, porod_const=2)
-        
+
         # Test results
         self.assertAlmostEquals(qstar, 7.88981e-5,2)
         self.assertAlmostEquals(v, 0.005952674, 3)
         self.assertAlmostEquals(s , 941.7452, 3)
-      
+
     def test_use_case_6(self):
         """
@@ -243,12 +251,12 @@
         # Create invariant object. Background and scale left as defaults.
         inv = invariant.InvariantCalculator(data=self.data)
-        
+
         # Set the extrapolation parameters for the high-Q range
         inv.set_extrapolation(range='low', npts=10, function='power_law', power=4)
-        
+
         # The version of the call without error
         # The function parameter defaults to None, then is picked to be 'power_law' for extrapolation='high'
         qstar = inv.get_qstar(extrapolation='low')
-        
+
         # The version of the call with error
         qstar, qstar_err = inv.get_qstar_with_error(extrapolation='low')
@@ -257,10 +265,11 @@
         v, dv = inv.get_volume_fraction_with_error(contrast=2.6e-6)
         s, ds = inv.get_surface_with_error(contrast=2.6e-6, porod_const=2)
-        
+
         # Test results
         self.assertAlmostEquals(qstar, 7.49e-5,2)
         self.assertAlmostEquals(v, 0.005952674, 3)
         self.assertAlmostEquals(s , 941.7452, 3)
-        
+
+
 class TestInvPinholeSmear(unittest.TestCase):
     """
@@ -271,5 +280,5 @@
         list = Loader().load("latex_smeared.xml")
         self.data_q_smear = list[0]
-    
+
     def test_use_case_1(self):
         """
@@ -278,5 +287,5 @@
         inv = invariant.InvariantCalculator(data=self.data_q_smear)
         qstar = inv.get_qstar()
-        
+
         v = inv.get_volume_fraction(contrast=2.6e-6)
         s = inv.get_surface(contrast=2.6e-6, porod_const=2)
@@ -285,5 +294,5 @@
         self.assertAlmostEquals(v, 0.115352622, 2)
         self.assertAlmostEquals(s , 941.7452, 3 )
-        
+
     def test_use_case_2(self):
         """
@@ -293,5 +302,5 @@
         # Create invariant object. Background and scale left as defaults.
         inv = invariant.InvariantCalculator(data=self.data_q_smear)
-        
+
         # Get the invariant with errors
         qstar, qstar_err = inv.get_qstar_with_error()
@@ -303,5 +312,5 @@
         self.assertAlmostEquals(v, 0.115352622, 2)
         self.assertAlmostEquals(s , 941.7452, 3 )
-       
+
     def test_use_case_3(self):
         """
@@ -319,10 +328,10 @@
         v, dv = inv.get_volume_fraction_with_error(contrast=2.6e-6)
         s, ds = inv.get_surface_with_error(contrast=2.6e-6, porod_const=2)
-        
+
         # Test results
         self.assertAlmostEquals(qstar, 0.00138756,2)
         self.assertAlmostEquals(v, 0.117226896,2)
         self.assertAlmostEquals(s ,941.7452, 3)
-      
+
     def test_use_case_4(self):
         """
@@ -337,16 +346,8 @@
         # The version of the call with error
         qstar, qstar_err = inv.get_qstar_with_error(extrapolation='high')
-        
-        # Get the volume fraction and surface
-        # WHY SHOULD THIS FAIL?
-        #self.assertRaises(RuntimeError, inv.get_volume_fraction_with_error, 2.6e-6)
-        
-        # Check that an exception is raised when the 'surface' is not defined
-        # WHY SHOULD THIS FAIL?
-        #self.assertRaises(RuntimeError, inv.get_surface_with_error, 2.6e-6, 2)
 
         # Test results
         self.assertAlmostEquals(qstar, 0.0045773,2)
-       
+
     def test_use_case_5(self):
         """
@@ -357,16 +358,13 @@
         # Set the extrapolation parameters for the low- and high-Q ranges
         inv.set_extrapolation(range='low', npts=10, function='guinier')
-        inv.set_extrapolation(range='high', npts=10, function='power_law', power=4)
-        # The version of the call without error
-        # The function parameter defaults to None, then is picked to be 'power_law' for extrapolation='high'
+        inv.set_extrapolation(range='high', npts=10, function='power_law',
+                              power=4)
+        # The version of the call without error
+        # The function parameter defaults to None, then is picked to be
+        # 'power_law' for extrapolation='high'
         qstar = inv.get_qstar(extrapolation='both')
         # The version of the call with error
         qstar, qstar_err = inv.get_qstar_with_error(extrapolation='both')
-        
-        # Get the volume fraction and surface
-        # WHY SHOULD THIS FAIL?
-        #self.assertRaises(RuntimeError, inv.get_volume_fraction_with_error, 2.6e-6)
-        #self.assertRaises(RuntimeError, inv.get_surface_with_error, 2.6e-6, 2)
-        
+
         # Test results
         self.assertAlmostEquals(qstar, 0.00460319,3)
