Source code for ship.utils.fileloaders.datloader

"""

 Summary:
    Factory class for building the AUnits from an ISIS data file.
    This is used to read and build the parts of the ISIS dat file.

 Author:  
     Duncan Runnacles

  Created:  
     01 Apr 2016

 Copyright:  
     Duncan Runnacles 2016

 TODO:
    There are a few functions in here that should be made protected. This
    doesn't really make much difference in Python in terms of encapsulation,
    but it makes it a bit clearer to any calling scripts that they might be
    messing with something that they probablly shouldn't be messing with.
    
    Comments are a bit over the top in this file. Need to go through and
    decide what is helpful and what is just getting in the way.

 Updates:

"""
from __future__ import unicode_literals

import os

from ship.utils.atool import ATool
from ship.utils.fileloaders.loader import ALoader
from ship.utils import filetools as ftools
from ship.fmp.fmpunitfactory import FmpUnitFactory
from ship.utils import utilfunctions as uf
from ship.fmp.datunits.isisunit import UnknownUnit
from ship.fmp.datcollection import DatCollection

import logging
logger = logging.getLogger(__name__)
"""logging references with a __name__ set to this module."""


[docs]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.""" ATool.__init__(self) ALoader.__init__(self) logger.debug('Instantiating DatLoader') self.cur_no_of_units = 0 self.contents = [] # Contents of dat file self.temp_unit = None # AUnit self.is_ied = False # If used to load an .ied file self._ic_name_types = {} # 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 }
[docs] 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 'UnknownUnit' 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 UnknownUnit 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 contents = self.__loadFile(file_path) if(contents == False): raise IOError ('Unable to load file at: ' + file_path) return self.buildDat(contents, arg_dict)
[docs] def buildDat(self, contents, arg_dict={}): """ """ self.contents = contents # 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 = FmpUnitFactory() # 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.createUnitFromFile(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 UnknownUnit then create and reset if(in_unknown_section == True): self.createUnknownSection() self.updateSubContents() # Reset the reach for the UnknownUnit 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) i, self.temp_unit = unit_factory.createUnitFromFile(self.contents, i, 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
[docs] 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 UnknownUnit - Unit No: ' + str(self.cur_no_of_units)) self.temp_unit = UnknownUnit() self.temp_unit.readUnitData(self.unknown_data)
[docs] 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
[docs] 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') # Don't update node count here as we aren't adding any 'new' nodes self.units.addUnit(self.temp_unit, update_node_count=False, no_copy=True) 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) contents = [] try: contents = ftools.getFile(filepath); except IOError: logger.error('IOError - Unable to load file') return False if(contents == None): logger.error('.DAT file is empty at: ' + filepath) return False return contents