def test_getUnit_method(self):
        '''Check we can safely get units by name.
        '''
        # Add some units to the collection
        col = DatCollection(self.path_holder)
        col.addUnit(self.river1)
        col.addUnit(self.river2)
        col.addUnit(self.header)

        # Get the unit we want
        river_unit = col.getUnit('1.067')

        # Make sure that it's right.
        self.assertTrue(river_unit.name == '1.067',
                        'Get River unit by name fail')

        # Get the header unit.
        header_unit = col.getUnit('Header')

        # Check it.
        self.assertTrue(header_unit.name == 'Header',
                        'Get header unit by name fail')

        # Remove all the units
        for u in col.units:
            del u

        # Make sure we got nothing
        no_unit = col.getUnit('River')
        self.assertFalse(no_unit, 'Get non existent unit fail')
    def test_getNoOfUnits_method(self):
        '''Make sure that it's returning the correct number of units.
        '''
        # Add some units to the collection
        col = DatCollection(self.path_holder)
        col.addUnit(self.river1)
        col.addUnit(self.river2)
        col.addUnit(self.header)

        # Get the number of units
        no_units = col.getNoOfUnits()

        # check that it's correct.
        self.assertTrue(no_units == 3, 'Get number of units fail')
    def test_getUnitsByCategory(self):
        '''Checks that we can safely return units by category.
        '''
        # Add some units to the collection
        col = DatCollection(self.path_holder)
        col.addUnit(self.river1)
        col.addUnit(self.river2)
        col.addUnit(self.header)

        # Get the river units.
        river_cat = col.getUnitsByCategory('River')
        # Make sure we have the number that we think we should have
        self.assertTrue(len(river_cat) == 2, 'Number of river units fail')

        # Get the head unit
        header_cat = col.getUnitsByCategory('Meta')
        # Check that we only have one
        self.assertTrue(len(header_cat) == 1, 'Number of header units fail')

        # Try a non existent category
        non_cat = col.getUnitsByCategory('redherring')
        self.assertFalse(non_cat, 'Number of red herring units fail')
    def test_removeUnit_method(self):
        '''Make sure that we can safely remove units
        '''
        # Add a couple of units
        col = DatCollection(self.path_holder)
        col.addUnit(self.river1)
        col.addUnit(self.river2)

        # Remove a unit
        self.assertTrue(col.removeUnit(self.river1.name),
                        'Cannot remove river1 unit fail')
        self.assertTrue(col.removeUnit(self.river2.name),
                        'Cannot remove river2 unit fail')
        self.assertFalse(col.removeUnit(self.river1.name),
                         'Remove non existing unit fail')
    def test_addUnit_method(self):
        '''Check what happens when we try and add a few units
        '''
        # Create a new IsisUnitCollection object
        col = DatCollection(self.path_holder)

        # Add a unit to the class
        col.addUnit(self.river1)

        # Check that it was successfully loaded into the collection
        self.assertTrue(col.units[0].name == '1.067',
                        'addUnit Test - cannot retrieve name fail')

        # Make sure we can't put the wrong kind of object in there.
        redherring = {}
        self.assertRaises(AttributeError, lambda: col.addUnit(redherring))

        # Make sure that out of bounds errors are caught.
        self.assertRaises(IndexError, lambda: col.addUnit(self.river2, 3))
Beispiel #6
0
    def loadFile(self, file_path, arg_dict={}):
        """Loads the ISIS .DAT file.

        Splits it into objects for each unit type, initial conditions etc.

        This is an epic if-else section for each unit type currently 
        represented.

        Needs cleaning up and writing with a bit more style.

        Easy to add another unit type, if it's not currently covered then it 
        will just be collected in the universal 'UnknownSection' and printed 
        back out the same as it came in.
        
        Args:
            file_path (str): path to the .dat file to load.
        
        Returns:
            units - UnitCollection containing the dat file units or False if 
                they couldn't be loaded.
        
        Raises:
            IOError: If the file cannot be loaded or is empty.
            AttributeError: if the file is not of an expected type (.dat/.ief).
        
        See Also:
            IsisUnitCollection
            FactoryClasses
        
        TODO: Decide if the observer style calls are ever going to be needed.
                If they aren't then remove them rather than have them
                cluttering up the file.
        """
        line = ''
        # Used to populate the data for the UnknownSection
        self.unknown_data = []
        # Composite for all dat units
        path_holder = ftools.PathHolder(file_path)
        self.units = DatCollection(path_holder)
        self.units.file_dir, self.units.filename = os.path.split(file_path)
        self.units.filename = os.path.splitext(self.units.filename)[0]

        if not uf.checkFileType(file_path, ext=['.dat', '.DAT']):
            if not uf.checkFileType(file_path, ext=['.ied', '.IED']):
                logger.error(
                    'Illegal File Error: ' + file_path +
                    '\nDoes not have extension (.dat, .DAT, .ied, .IED)')
                raise AttributeError(
                    'Illegal File Error: ' + file_path +
                    '\nDoes not have extension (.dat, .DAT, .ied, .IED)')
            else:
                self.is_ied = True

        if (self.__loadFile(file_path) == False):
            raise IOError('Unable to load file at: ' + file_path)

        # Counter for the number of rows that have been read from the
        # file contents list.
        i = 0
        # Get an instance of the unit factory with the number of nodes in the file.
        unit_factory = IsisUnitFactory()

        # Dictionary containing the keys to identify units in the dat file
        unit_vars = unit_factory.getUnitIdentifiers()

        # Create a unit from the header data in the first few lines of the dat file.
        if not self.is_ied:
            i, self.temp_unit = unit_factory.createUnit(
                self.contents, 0, 'header', 0)
            in_unknown_section = False

            # Now we can update the HeaderUnit subContents
            self.updateSubContents()

        in_unknown_section = False
        while i < len(self.contents):

            # Get the line and then split it to retrieve the first word.
            # Check this word against the # unit_type keys we set above to see
            line = self.contents[i]
            temp_line = line.strip()
            if temp_line:
                first_word = line.split()[0].strip()
            else:
                first_word = 'Nothing'

            if first_word in unit_vars:

                # If building an UnknownSection then create an reset
                if (in_unknown_section == True):
                    self.createUnknownSection()
                    self.updateSubContents()

                    # Reset the reach for the UnknownSection
                    unit_factory.same_reach = False
                '''Call the unit creator function and get back the unit and the
                updated contents list index.
                Most of these variables are self explanatory, but 
                unit_vars[first_word] is the key for the unit type to make.
                '''
                i, self.temp_unit = unit_factory.createUnit(
                    self.contents, i, unit_vars[first_word],
                    self.cur_no_of_units)
                '''In case we got in but found something wasn't supported.
                it's i-1 because we can't return onto the same line that was
                read or it will loop forever, so store it here and move on
                '''
                if self.temp_unit == False:
                    self.unknown_data.append(self.contents[i].rstrip('\n'))
                    i += 1
                    self.unknown_data.append(self.contents[i].rstrip('\n'))
                    in_unknown_section = True
                else:
                    self.updateSubContents()
                    in_unknown_section = False

            else:
                in_unknown_section = True
                self.unknown_data.append(self.contents[i].rstrip('\n'))

            i += 1

        line = None
        del self.unknown_data
        return self.units
Beispiel #7
0
class DatLoader(ATool, ALoader):
    """
    Isis data file (.DAT) I/O methods.

    Factory for creating the .DAT file objects.
    Identifies different section of the .DAT file and creates objects of
    the different units. Also saves updated file.

    All unknown data within the file is contained within UnkownSection units. 
    These read in the text as found and write out as found, with no knowledge 
    of the contents. Effectively bypassing the need to worry about parts that 
    aren't being used yet.
    """
    def __init__(self):
        """Constructor."""

        logger.debug('Instantiating DatLoader')

        self.cur_no_of_units = 0
        self.contents = []  # Contents of dat file
        self.temp_unit = None  # AIsisUnit
        self.is_ied = False  # If used to load an .ied file

        # reach_info dictionary. Keeps track of the information needed to identify
        # reach status. Contains:
        # [0] = counter - iterated every time a new reach is started.
        # [1] = same reach status - keeps track of whether it's in an existing
        #       reach or starting a new one.
        self.reach_info = {'Reach_number': 0, 'Same_reach': False}

    def loadFile(self, file_path, arg_dict={}):
        """Loads the ISIS .DAT file.

        Splits it into objects for each unit type, initial conditions etc.

        This is an epic if-else section for each unit type currently 
        represented.

        Needs cleaning up and writing with a bit more style.

        Easy to add another unit type, if it's not currently covered then it 
        will just be collected in the universal 'UnknownSection' and printed 
        back out the same as it came in.
        
        Args:
            file_path (str): path to the .dat file to load.
        
        Returns:
            units - UnitCollection containing the dat file units or False if 
                they couldn't be loaded.
        
        Raises:
            IOError: If the file cannot be loaded or is empty.
            AttributeError: if the file is not of an expected type (.dat/.ief).
        
        See Also:
            IsisUnitCollection
            FactoryClasses
        
        TODO: Decide if the observer style calls are ever going to be needed.
                If they aren't then remove them rather than have them
                cluttering up the file.
        """
        line = ''
        # Used to populate the data for the UnknownSection
        self.unknown_data = []
        # Composite for all dat units
        path_holder = ftools.PathHolder(file_path)
        self.units = DatCollection(path_holder)
        self.units.file_dir, self.units.filename = os.path.split(file_path)
        self.units.filename = os.path.splitext(self.units.filename)[0]

        if not uf.checkFileType(file_path, ext=['.dat', '.DAT']):
            if not uf.checkFileType(file_path, ext=['.ied', '.IED']):
                logger.error(
                    'Illegal File Error: ' + file_path +
                    '\nDoes not have extension (.dat, .DAT, .ied, .IED)')
                raise AttributeError(
                    'Illegal File Error: ' + file_path +
                    '\nDoes not have extension (.dat, .DAT, .ied, .IED)')
            else:
                self.is_ied = True

        if (self.__loadFile(file_path) == False):
            raise IOError('Unable to load file at: ' + file_path)

        # Counter for the number of rows that have been read from the
        # file contents list.
        i = 0
        # Get an instance of the unit factory with the number of nodes in the file.
        unit_factory = IsisUnitFactory()

        # Dictionary containing the keys to identify units in the dat file
        unit_vars = unit_factory.getUnitIdentifiers()

        # Create a unit from the header data in the first few lines of the dat file.
        if not self.is_ied:
            i, self.temp_unit = unit_factory.createUnit(
                self.contents, 0, 'header', 0)
            in_unknown_section = False

            # Now we can update the HeaderUnit subContents
            self.updateSubContents()

        in_unknown_section = False
        while i < len(self.contents):

            # Get the line and then split it to retrieve the first word.
            # Check this word against the # unit_type keys we set above to see
            line = self.contents[i]
            temp_line = line.strip()
            if temp_line:
                first_word = line.split()[0].strip()
            else:
                first_word = 'Nothing'

            if first_word in unit_vars:

                # If building an UnknownSection then create an reset
                if (in_unknown_section == True):
                    self.createUnknownSection()
                    self.updateSubContents()

                    # Reset the reach for the UnknownSection
                    unit_factory.same_reach = False
                '''Call the unit creator function and get back the unit and the
                updated contents list index.
                Most of these variables are self explanatory, but 
                unit_vars[first_word] is the key for the unit type to make.
                '''
                i, self.temp_unit = unit_factory.createUnit(
                    self.contents, i, unit_vars[first_word],
                    self.cur_no_of_units)
                '''In case we got in but found something wasn't supported.
                it's i-1 because we can't return onto the same line that was
                read or it will loop forever, so store it here and move on
                '''
                if self.temp_unit == False:
                    self.unknown_data.append(self.contents[i].rstrip('\n'))
                    i += 1
                    self.unknown_data.append(self.contents[i].rstrip('\n'))
                    in_unknown_section = True
                else:
                    self.updateSubContents()
                    in_unknown_section = False

            else:
                in_unknown_section = True
                self.unknown_data.append(self.contents[i].rstrip('\n'))

            i += 1

        line = None
        del self.unknown_data
        return self.units

    def createUnknownSection(self):
        """Builds unidentified sections from the .DAT file.

        All currently un-dealt-with sections of the .DAT file are
        incorporated into this.
        Loads in chunks of the file 'as-is' and prints them out the same way.
        """
        logger.debug('Creating UnknownSection - Unit No:  ' +
                     str(self.cur_no_of_units))
        self.temp_unit = UnknownSection(self.cur_no_of_units)
        self.temp_unit.readUnitData(self.unknown_data)

    def getUnits(self):
        """Getter for imported units
        
        Note:
            Deprecated: Will be removed. Please use self.units directly.
        
        Returns:
            IsisUnitCollection - The units loaded from the dat file. 
        """
        return self.units

    def updateSubContents(self):
        """Updates the self.units.
        
        Appends the new temp_unit to list of units and resets all the 
        variables.
        """
        #logger.debug('In updateSubContents')
        self.units.addUnit(self.temp_unit)
        self.cur_no_of_units += 1
        del self.temp_unit
        self.unknown_data = []

    def __loadFile(self, filepath):
        """Load the .dat file into the contents list.
        
        Args:
            filepath: Path to the required DAT file.
            
        Returns:
            True if loaded ok, False otherwise.
        """
        logger.info('loading File: ' + filepath)
        try:
            self.contents = ftools.getFile(filepath)
        except IOError:
            logger.error('IOError - Unable to load file')
            return False

        if (self.contents == None):
            logger.error('.DAT file is empty at: ' + filepath)
            return False

        return True
    def test_getPrintableContents(self):
        '''Ensure that the printable lists are in the format that we are
        expecting.
        '''
        # Make comparable out contents
        self.out_contents = \
        ['RIVER (Culvert Exit) CH:7932 - Trimmed to BT',
         'SECTION',
         '1.067',
         '    15.078            1.111111      1000',
         '        18',
         '     5.996    37.560     0.080     1.000LEFT       291391.67  86582.61LEFT      16        ',
         '     6.936    37.197     0.035*    1.000           291391.43  86581.70          ',
         '     7.446    36.726     0.035     1.000           291391.30  86581.21          ',
         '     7.635    35.235     0.035     1.000           291391.25  86581.03          ',
         '     8.561    35.196     0.035     1.000           291391.01  86580.13          ',
         '     9.551    35.190     0.035     1.000BED        291390.75  86579.18          ',
         '    10.323    35.229     0.035     1.000           291390.55  86578.43          ',
         '    10.904    35.319     0.035     1.000           291390.40  86577.87          ',
         '    12.542    35.637     0.035     1.000           291389.98  86576.29          ',
         '    13.740    35.593     0.035     1.000           291389.67  86575.13          ',
         '    13.788    35.592     0.035     1.000           291389.66  86575.09          ',
         '    13.944    36.148     0.035     1.000           291389.62  86574.93          ',
         '    15.008    36.559     0.080*    1.000           291389.34  86573.91          ',
         '    16.355    37.542     0.080     1.000           291389.00  86572.60          ',
         '    17.424    38.518     0.080     1.000           291388.72  86571.57          ',
         '    18.449    39.037     0.080     1.000           291388.46  86570.58          ',
         '    19.416    39.146     0.080     1.000           291388.21  86569.65          ',
         '    19.420    39.133     0.080     1.000RIGHT      291388.21  86569.65RIGHT     4095      ',
         'RIVER (Culvert Exit) CH:7932 - Trimmed to BT',
         'SECTION',
         '1.068',
         '    15.078            1.111111      1000',
         '        18',
         '     5.996    37.560     0.080     1.000LEFT       291391.67  86582.61LEFT      16        ',
         '     6.936    37.197     0.035*    1.000           291391.43  86581.70          ',
         '     7.446    36.726     0.035     1.000           291391.30  86581.21          ',
         '     7.635    35.235     0.035     1.000           291391.25  86581.03          ',
         '     8.561    35.196     0.035     1.000           291391.01  86580.13          ',
         '     9.551    35.190     0.035     1.000BED        291390.75  86579.18          ',
         '    10.323    35.229     0.035     1.000           291390.55  86578.43          ',
         '    10.904    35.319     0.035     1.000           291390.40  86577.87          ',
         '    12.542    35.637     0.035     1.000           291389.98  86576.29          ',
         '    13.740    35.593     0.035     1.000           291389.67  86575.13          ',
         '    13.788    35.592     0.035     1.000           291389.66  86575.09          ',
         '    13.944    36.148     0.035     1.000           291389.62  86574.93          ',
         '    15.008    36.559     0.080*    1.000           291389.34  86573.91          ',
         '    16.355    37.542     0.080     1.000           291389.00  86572.60          ',
         '    17.424    38.518     0.080     1.000           291388.72  86571.57          ',
         '    18.449    39.037     0.080     1.000           291388.46  86570.58          ',
         '    19.416    39.146     0.080     1.000           291388.21  86569.65          ',
         '    19.420    39.133     0.080     1.000RIGHT      291388.21  86569.65RIGHT     4095      ']

        # Add a couple of units
        col = DatCollection(self.path_holder)
        col.addUnit(self.river1)
        col.addUnit(self.river2)

        # Get the printable units from the collection
        print_unit = col.getPrintableContents()

        # Make sure the printed units are what we expect
        self.assertListEqual(self.out_contents, print_unit,
                             'GetPrintable units fail')