PokeyConfig

#*****************************PokeyConfig*******************************

class PokeyConfig(object):

    """ PokeyConfig is a multi-language configuration file class """

    #Supported formats :
    #    Python
    #    JSON
    #    YAML
    #    Delimited

    # Enable delimited mode by passing a delimiter in the type
    pipe = '|'
    tab = '\t'
    semicolon = ';'
    comma = ','
    percent = '%'

    delimiters = [pipe,tab,semicolon,comma]

    # Available formats
    json = 1
    yaml = 2

    def __init__(self,fpath,conf_type=1,auto_apply=False):

        if not JSON_ENABLED or not YAML_ENABLED:
            mname = "pyyaml" if not YAML_ENABLED else "json"
            raise AssertionError("Missing Dependency: {}".format(mname))
        try:
            self.fpath = fpath
            self.load_config(conf_type)
            self.loaded_type = conf_type
            if auto_apply:
                self.apply_config()
        except Exception as e:
            raise

    def apply_config(self):
        # Creates class attributes from dictionary pairs
        # (Optional)

        for key in self.conf_dict:
            setattr(self,key,self.conf_dict[key])

    def load_json(self,fpath):
        assert fpath.endswith(".json"),"Invalid file path to load as JSON"
        with open(fpath) as json_data:
            retval = json.load(json_data)

        return retval

    def load_yaml(self,fpath):
        assert fpath.endswith(".yaml"),"Invalid file path to load as YAML"
        with open(fpath) as yaml_data:
            retval = yaml.safe_load(yaml_data)

        return retval

    def save_json(self,fpath,conf_dict):
        assert fpath.endswith(".json"),"Invalid file path to save as JSON"
        try:
            with open(fpath,'w') as json_out:
                json.dump(conf_dict,json_out)
        except Exception as e:
            retval = e
        else:
            retval = True

    def save_yaml(self,fpath,conf_dict):
        assert fpath.endswith(".yaml"),"Invalid file path to save as YAML"
        try:
            with open(fpath,'w') as yaml_out:
                yaml.dump(conf_dict,yaml_out)
        except Exception as e:
            retval = e
        else:
            reval = True

    def convert_file_path(self,inpath,suffix):
        file_base = inpath.split('.')[:-1]
        file_base.append(suffix)
        return '.'.join(file_base)

    def convert_delimited(self,inpath,out_type):

        if out_type is PokeyConfig.json:
            suffix = 'json'
            write_method = self.save_json
            read_method = self.load_json
        elif out_type is PokeyConfig.yaml:
            suffix = 'yaml'
            write_method = self.save_yaml
            read_method = self.load_yaml
        else:
            raise AssertionError('Invalid Output Type: {}'.format(out_type))

        opath = self.convert_file_path(inpath,suffix)
        write_method(opath,self.conf_dict)

        # Test twice before failing
        if not self.verify_conversion(read_method(opath)):
            if not self.verify_conversion(read_method(opath)):
                raise AssertionError('Conversion Error! Please log and report')

        return read_method(opath)

    def write_config(self,**kw):

        if self.loaded_type == PokeyConfig.json:
            write_method = self.save_json
        elif self.loaded_type == PokeyConfig.yaml:
            write_method = self.save_yaml

        write_method(self.fpath,self.conf_dict)

    def verify_conversion(self,compare_dict):

        for key in self.conf_dict:
            try:
                print key
                print self.conf_dict[key]
                assert compare_dict[key]==self.conf_dict[key], \
                    "Conversion error! Retrying (val:{}|comp:{})".format(
                                                        val,compare_dict[key]
                                                        )
            except AssertionError,KeyError:
                return False
        return True

    def load_config(self,conf_type,inpath=None):

        if inpath is None:
            inpath=self.fpath
        if conf_type not in [PokeyConfig.json,PokeyConfig.yaml]:
            print "[*] Legacy PokeyConfig configuration detected!"
            while True:
                print "\tConvert to [J]SON"
                print "\tConvert to [Y]AML"
                choice = raw_input("\tSelection > ")
                if choice.upper() == 'J':
                    out_type = PokeyConfig.json
                    break
                elif choice.upper() == 'Y':
                    out_type = PokeyConfig.yaml
                    break
                else:
                    print "[*] Invalid choice!  Conversion is required"

            self.load_delimited(inpath,conf_type)
            new_config = self.convert_delimited(inpath,out_type)

        elif conf_type == PokeyConfig.json:
            self.conf_dict = self.load_json(inpath)

        elif conf_type == PokeyConfig.yaml:
            self.conf_dict = self.load_yaml(inpath)
        else:
            raise AssertionError("Invalid config type {}".format(conf_type))

        return True

    def load_delimited(self,inpath,delimiter):
        # Default delimiter for PokeyWorks applications was %

        self.conf_dict = {}

        with open(inpath, 'rb') as c:
            data = c.readlines()

        for row in data:
            if "#" not in row and row.strip():
                vals = row.rstrip().split(delimiter)
                self.conf_dict[vals[0]] = vals[1]
                print self.conf_dict