| Total Complexity | 77 | 
| Total Lines | 227 | 
| Duplicated Lines | 0 % | 
Complex classes like doorpi.conf.ConfigObject often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
| 1 | #!/usr/bin/env python  | 
            ||
| 15 | class ConfigObject():  | 
            ||
| 16 | |||
| 17 |     __sections = {} | 
            ||
| 18 | _config_file = None  | 
            ||
| 19 | |||
| 20 | @property  | 
            ||
| 21 | def all(self): return self.__sections  | 
            ||
| 22 | |||
| 23 | @property  | 
            ||
| 24 | def config_file(self): return self._config_file  | 
            ||
| 25 | |||
| 26 | def __init__(self, config, config_file = None):  | 
            ||
| 27 |         logger.debug("__init__") | 
            ||
| 28 | self.get_from_config(config)  | 
            ||
| 29 | self._config_file = config_file  | 
            ||
| 30 | |||
| 31 | def __del__(self):  | 
            ||
| 32 | return self.destroy()  | 
            ||
| 33 | |||
| 34 | def destroy(self):  | 
            ||
| 35 |         logger.debug("__del__") | 
            ||
| 36 | #DoorPi().event_handler.unregister_source(__name__, True)  | 
            ||
| 37 | return True  | 
            ||
| 38 | |||
| 39 | @staticmethod  | 
            ||
| 40 | def find_config(configfile = None):  | 
            ||
| 41 | try:  | 
            ||
| 42 | open(configfile.name, 'r').close()  | 
            ||
| 43 | return configfile.name  | 
            ||
| 44 | except AttributeError: pass  | 
            ||
| 45 | except IOError: pass  | 
            ||
| 46 | |||
| 47 | default_files = [  | 
            ||
| 48 | str(configfile),  | 
            ||
| 49 | doorpi.DoorPi().parse_string(str(configfile)),  | 
            ||
| 50 |             os.path.join('!BASEPATH!', 'conf', 'doorpi.ini'), | 
            ||
| 51 |             os.path.join('!BASEPATH!', 'conf', 'doorpi.cfg') | 
            ||
| 52 | ]  | 
            ||
| 53 | |||
| 54 | for possible_default_file in default_files:  | 
            ||
| 55 | try:  | 
            ||
| 56 | possible_default_file = doorpi.DoorPi().parse_string(possible_default_file)  | 
            ||
| 57 | open(possible_default_file, 'r').close()  | 
            ||
| 58 | return possible_default_file  | 
            ||
| 59 | except: pass  | 
            ||
| 60 | |||
| 61 | return None  | 
            ||
| 62 | |||
| 63 | @staticmethod  | 
            ||
| 64 | def load_config(configfile, search_for_defaults = True):  | 
            ||
| 65 | config = ConfigParser.ConfigParser(allow_no_value = True)  | 
            ||
| 66 | if search_for_defaults: configfile_name = ConfigObject.find_config(configfile)  | 
            ||
| 67 | else: configfile_name = configfile  | 
            ||
| 68 | |||
| 69 | if not configfile_name:  | 
            ||
| 70 |             logger.error('No valid configfile found - use parameter --configfile "filename" to specify one') | 
            ||
| 71 | return ConfigObject(config)  | 
            ||
| 72 | |||
| 73 |         logger.info("use configfile: %s", configfile_name) | 
            ||
| 74 | |||
| 75 | config.read(configfile_name)  | 
            ||
| 76 | return ConfigObject(config, configfile_name)  | 
            ||
| 77 | |||
| 78 | def save_config(self, configfile = ''):  | 
            ||
| 79 | if not configfile: configfile = self.config_file  | 
            ||
| 80 | if not configfile: configfile = self.find_config(configfile)  | 
            ||
| 81 |         if not configfile: configfile = doorpi.DoorPi().parse_string(os.path.join('!BASEPATH!', 'conf', 'doorpi.ini')) | 
            ||
| 82 | |||
| 83 | #if not configfile: return False  | 
            ||
| 84 |         logger.debug("write configfile: %s", configfile) | 
            ||
| 85 | try:  | 
            ||
| 86 | if not os.path.exists(os.path.dirname(configfile)):  | 
            ||
| 87 |                 logger.info('Path %s does not exist - creating it now', os.path.dirname(configfile)) | 
            ||
| 88 | os.makedirs(os.path.dirname(configfile))  | 
            ||
| 89 | cfgfile = open(configfile,'w')  | 
            ||
| 90 | config = ConfigParser.ConfigParser(allow_no_value = True)  | 
            ||
| 91 | for section in sorted(self.__sections.keys()):  | 
            ||
| 92 | config.add_section(section)  | 
            ||
| 93 | for key in sorted(self.__sections[section].keys()):  | 
            ||
| 94 | config.set(section, key, self.__sections[section][key])  | 
            ||
| 95 | config.write(cfgfile)  | 
            ||
| 96 | cfgfile.close()  | 
            ||
| 97 |             logger.info("write configfile was success: %s", configfile) | 
            ||
| 98 | return True  | 
            ||
| 99 | except Exception as exp:  | 
            ||
| 100 | logger.exception(exp)  | 
            ||
| 101 | return False  | 
            ||
| 102 | |||
| 103 | def get_string_parsed(self, section, key, default = '', log = True):  | 
            ||
| 104 | raw_string = self.get_string(section, key, default, log)  | 
            ||
| 105 | parsed_string = doorpi.DoorPi().parse_string(raw_string)  | 
            ||
| 106 |         logger.debug('parse string "%s" to "%s"', raw_string, parsed_string) | 
            ||
| 107 | return parsed_string  | 
            ||
| 108 | |||
| 109 | def set_value(self, section, key, value, log = True, password = False):  | 
            ||
| 110 | if section not in self.__sections.keys():  | 
            ||
| 111 |             self.__sections[section] = {} | 
            ||
| 112 | |||
| 113 | password_friendly_value = "*******" if key is 'password' or password else value  | 
            ||
| 114 | |||
| 115 | if key not in self.__sections[section].keys():  | 
            ||
| 116 |             if log: logger.debug("create new key %s in section %s with value '%s'", | 
            ||
| 117 | key, section, password_friendly_value)  | 
            ||
| 118 | else:  | 
            ||
| 119 |             if log: logger.debug("overwrite key %s in section %s from '%s' to '%s'", | 
            ||
| 120 | key, section, self.__sections[section][key], password_friendly_value)  | 
            ||
| 121 | |||
| 122 | self.__sections[section][key] = value  | 
            ||
| 123 | return True  | 
            ||
| 124 | |||
| 125 | def rename_key(self, section, old_key, new_key, default = '', log = True):  | 
            ||
| 126 |         if log: logging.debug('rename key from %s to %s in section %s', old_key, new_key, section) | 
            ||
| 127 | old_value = self.get_string(section, old_key, default, log, store_if_not_exists = False)  | 
            ||
| 128 | self.set_value(  | 
            ||
| 129 | section = section,  | 
            ||
| 130 | key = new_key,  | 
            ||
| 131 | value = old_value,  | 
            ||
| 132 | log = log  | 
            ||
| 133 | )  | 
            ||
| 134 | self.delete_key(section, old_key, log = log)  | 
            ||
| 135 | |||
| 136 | def delete_section(self, section, delete_empty_only = True, log = True):  | 
            ||
| 137 | if section in self.__sections and len(self.__sections[section]) > 0 and delete_empty_only:  | 
            ||
| 138 |             logger.warning("could not delete section %s, because it's not empty.", section) | 
            ||
| 139 | return False  | 
            ||
| 140 | |||
| 141 | try:  | 
            ||
| 142 | if len(self.__sections[section]) > 0 and delete_empty_only:  | 
            ||
| 143 |                 raise KeyError('section is not empty') | 
            ||
| 144 | |||
| 145 | self.__sections.pop(section)  | 
            ||
| 146 | return True  | 
            ||
| 147 | except KeyError as exp:  | 
            ||
| 148 |             if log: logger.warning('delete section %s failed: %s', section, exp) | 
            ||
| 149 | return False  | 
            ||
| 150 | |||
| 151 | def delete_key(self, section, key, log = True):  | 
            ||
| 152 | try:  | 
            ||
| 153 |             if log: logger.info('delete key %s from section %s', key, section) | 
            ||
| 154 | self.__sections[section].pop(key)  | 
            ||
| 155 | self.delete_section(section, log = log)  | 
            ||
| 156 | |||
| 157 | return True  | 
            ||
| 158 | except KeyError as exp:  | 
            ||
| 159 |             if log: logger.warning('delete key %s from section %s failed: %s', key, section, exp) | 
            ||
| 160 | return False  | 
            ||
| 161 | |||
| 162 | def get_string(self, section, key, default = '', log = True, password = False, store_if_not_exists = True):  | 
            ||
| 163 | value = None  | 
            ||
| 164 | try:  | 
            ||
| 165 | old_section, old_key = BACKWARD_COMPATIBILITY_KEYS[section][key]  | 
            ||
| 166 | value = self.__sections[old_section][old_key]  | 
            ||
| 167 | self.delete_key(old_section, old_key, False)  | 
            ||
| 168 | self.__sections[section][key] = value  | 
            ||
| 169 |             logger.warning('found %s - %s in BACKWARD_COMPATIBILITY_KEYS with %s - %s', section, key, old_section, old_key) | 
            ||
| 170 | except KeyError:  | 
            ||
| 171 | try:  | 
            ||
| 172 | value = self.__sections[section][key]  | 
            ||
| 173 | except KeyError:  | 
            ||
| 174 | pass  | 
            ||
| 175 | |||
| 176 | if value is None:  | 
            ||
| 177 |             #logger.trace('no value found - use default') | 
            ||
| 178 | value = default  | 
            ||
| 179 | if store_if_not_exists: self.set_value(section, key, default, log, password)  | 
            ||
| 180 | |||
| 181 |         if key.endswith('password') or password: | 
            ||
| 182 |             if log: logger.trace("get_string for key %s in section %s (default: %s) returns %s", key, section, default, '*******') | 
            ||
| 183 | else:  | 
            ||
| 184 |             if log: logger.trace("get_string for key %s in section %s (default: %s) returns %s", key, section, default, value) | 
            ||
| 185 | return value  | 
            ||
| 186 | |||
| 187 | def get_float(self, section, key, default = -1, log = True, store_if_not_exists = True):  | 
            ||
| 188 | value = self.get_string(section, key, str(default), log = False, store_if_not_exists = store_if_not_exists)  | 
            ||
| 189 | if value is not '': value = float(value)  | 
            ||
| 190 | else: value = default  | 
            ||
| 191 |         if log: logger.trace("get_integer for key %s in section %s (default: %s) returns %s", key, section, default, value) | 
            ||
| 192 | return value  | 
            ||
| 193 | |||
| 194 | def get_integer(self, section, key, default = -1, log = True, store_if_not_exists = True):  | 
            ||
| 195 | value = self.get(section, key, str(default), log = False, store_if_not_exists = store_if_not_exists)  | 
            ||
| 196 | if value is not '': value = int(value)  | 
            ||
| 197 | else: value = default  | 
            ||
| 198 |         if log: logger.trace("get_integer for key %s in section %s (default: %s) returns %s", key, section, default, value) | 
            ||
| 199 | return value  | 
            ||
| 200 | |||
| 201 | def get_boolean(self, section, key, default = False, log = True, store_if_not_exists = True):  | 
            ||
| 202 | value = self.get(section, key, str(default), log = False, store_if_not_exists = store_if_not_exists)  | 
            ||
| 203 | value = value.lower() in ['true', 'yes', 'ja', '1']  | 
            ||
| 204 |         if log: logger.trace("get_boolean for key %s in section %s (default: %s) returns %s", key, section, default, value) | 
            ||
| 205 | return value  | 
            ||
| 206 | |||
| 207 | def get_list(self, section, key, default = [], separator = ',', log = True, store_if_not_exists = True):  | 
            ||
| 208 | value = self.get(section, key, str(default), log = False, store_if_not_exists = store_if_not_exists)  | 
            ||
| 209 | if value is not '': value = value.split(separator)  | 
            ||
| 210 | else: value = default  | 
            ||
| 211 |         if log: logger.trace("get_list for key %s in section %s (default: %s) returns %s", key, section, default, value) | 
            ||
| 212 | return value  | 
            ||
| 213 | |||
| 214 | def get_sections(self, filter = '', log = True):  | 
            ||
| 
                                                                                                    
                        
                         | 
                |||
| 215 | return_list = []  | 
            ||
| 216 | for section in self.__sections:  | 
            ||
| 217 | if filter in section: return_list.append(section)  | 
            ||
| 218 |         if log: logger.trace("get_sections returns %s", return_list) | 
            ||
| 219 | return return_list  | 
            ||
| 220 | |||
| 221 | def get_keys(self, section, filter = '', log = True):  | 
            ||
| 222 | return_list = []  | 
            ||
| 223 | if section not in self.__sections:  | 
            ||
| 224 |             logging.warning("section %s not found in configfile", section) | 
            ||
| 225 | else:  | 
            ||
| 226 | for key in self.__sections[section]:  | 
            ||
| 227 | if filter in key: return_list.append(key)  | 
            ||
| 228 |         if log: logger.trace("get_keys for section %s returns %s", section, return_list) | 
            ||
| 229 | return return_list  | 
            ||
| 230 | |||
| 231 | def get_from_config(self, config, log = True):  | 
            ||
| 232 |         if log: logger.trace("get_from_config") | 
            ||
| 233 | for section in config.sections():  | 
            ||
| 234 |             self.__sections[section] = {} | 
            ||
| 235 | for key, value in config.items(section):  | 
            ||
| 236 |                 if key.startswith(';') or key.startswith('#'): continue | 
            ||
| 237 | self.__sections[section][str(key)] = str(value)  | 
            ||
| 238 | |||
| 239 | get = get_string  | 
            ||
| 240 | get_bool = get_boolean  | 
            ||
| 241 | get_int = get_integer  | 
            ||
| 242 | 
It is generally discouraged to redefine built-ins as this makes code very hard to read.