My first program is getting much bigger than excepted. :)
import configparser
config = configparser.ConfigParser()
configfile = 'RealGui.ini'
class FolderLeftSettings:
def __init__(self):
self.name = "SECTION"
self.last_directory = ""
self.row_size = 6
self.column_size = 9
def write_to_ini(self):
if not config.has_section(str(self.name)):
config.add_section(str(self.name))
with open('configfile', 'w') as configfile:
config.set(self.name, 'last_directory', str(self.last_directory))
config.set(self.name, 'row_size', str(self.row_size))
config.set(self.name, 'column_size', str(self.column_size))
config.write(configfile)
def read_from_ini(self):
try:
config.read('configfile')
if config.has_section(str(self.name)):
self.last_directory = (config[self.name]['last_directory'])
self.row_size = int((config[self.name]['row_size']))
self.column_size = int((config[self.name]['column_size']))
except Exception as e:
print("failed to read ini....overwriting with defaults")
print(e)
self.write_to_ini()
settings=FolderLeftSettings()
My problem was, that every setting from the init needs to be written manually in the 2 methods as well. I found the solution, and the answer is on the bottom. Working Example!
OK I finally solved it, and decided to share, in hope it helps someone else.
You can test it yourself....code is working even without a .ini file(will be created) Now I can add as many settings in init as I want, without editing the other 2 methods as well.
As a Bonus, now the values gets correctly parsed from the .ini into the variables. Meaning tuple will become tuple. Not supported normally from configparser. Additionally it checks whether the TYPE in the default section corresponds with the type inside the .ini...if not, ONLY the wrong line gets changed back to default. Except when str is expected, than all types in the ini pass. Which is somehow correct. Like a username is default a string, but custom username could be integer only, or even a tuple..lol. And if integer is expected, True and False pass as integer in ini, what is also technically correct..lol. But anything else gets found, eg. a broken tuple in the ini gets defaulted back, if a tuple is expected. If anything else is broken, ALL defaults are getting written. It supports the correct casting of (bool, tuple, int, float, set, dict, list) and of course str. Bool needed some special love,...now True/False upper/lowercase and inside "" or '' are supportet.
############################################### SETTINGS START ########################################################
import configparser
import logging.config
from ast import literal_eval
datatypes = (tuple, int, float, set, dict, list)
class Bcolors:
HEADER = "\033[95m"
OKBLUE = "\033[94m"
OKCYAN = "\033[96m"
OKGREEN = "\033[92m"
YELLOW = "\033[93m"
FAIL = "\033[91m"
ENDC = "\033[0m"
BOLD = "\033[1m"
UNDERLINE = "\033[4m"
class SettingsGeneral:
config = configparser.ConfigParser()
configfile = "RealGui.ini"
section = "GENERAL"
def __init__(self):
self.window_last_position = True
self.window_last_size = [1500, 1060]
self.filename_formatting = (33, 2) # (33, 2) #2 rows
self.graphics_directory = "G:\+++CODING+++\Thin-Plate-Spline-Motion-Model-Windows-main\RealGui\graphics\\"
self.extensions = (".gif", ".png", ".jpg")
def read_from_ini(self):
tmp = list(self.__dict__.items()) # This is the magic I was looking for. Need to be converted to a list, or a deep copy, because you cannot iterate over a dic and change it.
try:
self.config.read(self.configfile)
for attr_name, attr_value in tmp:
inivalue = self.config[self.section][attr_name]
datatype = type(attr_value)
if datatype == bool:
if ''.join(e for e in inivalue.lower() if e.isalnum()) == 'false':
setattr(self, attr_name, bool(False))
elif ''.join(e for e in inivalue.lower() if e.isalnum()) == 'true':
setattr(self, attr_name, bool(True))
else:
logging.warning(f"{Bcolors.FAIL}invalid .ini entry: {attr_name} = \"{inivalue}\" ...expected type {datatype} ...overwriting with default{Bcolors.ENDC}")
self.config.set(self.section, attr_name, str(attr_value))
elif datatype in datatypes:
try:
if isinstance(literal_eval(inivalue), datatype):
setattr(self, attr_name, literal_eval(inivalue))
else:
logging.warning(f"{Bcolors.FAIL}invalid .ini entry: {attr_name} = \"{inivalue}\" ...expected type {datatype} ...overwriting with default{Bcolors.ENDC}")
self.config.set(self.section, attr_name, str(attr_value))
except Exception as e:
logging.warning(f"{Bcolors.YELLOW}invalid .ini entry: {attr_name} = \"{inivalue}\" ....overwriting with default{Bcolors.ENDC}")
logging.warning(f"{Bcolors.FAIL}{e}{Bcolors.ENDC}")
self.config.set(self.section, attr_name, str(attr_value))
elif datatype == str:
if isinstance(inivalue, datatype):
setattr(self, attr_name, inivalue)
except Exception as e:
logging.warning(f"{Bcolors.FAIL}failed to read ini..Section:{self.section}....overwriting with defaults{Bcolors.ENDC}")
logging.warning(f"{Bcolors.FAIL}{e}{Bcolors.ENDC}")
self.write_to_ini()
def write_to_ini(self):
with open(self.configfile, "w") as cfg:
tmp = list(self.__dict__.items()) # This is the magic I was looking for. Need to be converted to a list, or a deep copy, because you cannot iterate over a dic and change it.
if not self.config.has_section(str(self.section)):
self.config.add_section(str(self.section))
for attr_name, attr_value in tmp:
self.config.set(self.section, attr_name, str(attr_value))
self.config.write(cfg)
class FolderLeftSettings(SettingsGeneral):
config = configparser.ConfigParser()
section = "FOLDER-LEFT"
configfile = "RealGui.ini"
def __init__(self):
self.last_directory = "C:\\"
self.row_size = 8
self.column_size = 9
############################################### SETTINGS END ########################################################
and in main it can be used normally like:
settings=FolderLeftSettings()
print(settings.last_directory) # Default Value according to __init__
settings.read_from_ini()
print(settings.last_directory) # if .ini is correctly read..show new value
settings.last_directory ="Z:\\"
settings.write_to_ini()
print(settings.last_directory) # New updated Value...no need to read from .ini again of course