This is a little settings module that I wrote a while ago to keep saving settings as simple as possible. In reality it’s just a wrapper to read/write stuff from/to a .json file, but you can use easy to read one liners.

The Singleton version relies on the Qt framework, so make sure you have that installed.

The Singleton version makes it very easy to call it once in the beginning of you script, after which you don’t need to make an instance of the class at any other place in your program.

import EasySettingsSingleton as settings

SETTINGS_PATH = "/home/nisse/scripts/demo_settings.json"

settings(SETTINGS_PATH)

class Riverdale(object):
    def __init__(self):
        super().__init__()
        settings().set_value("people_that_died", 66)
        settings().set_value("kids", ["Betty", "Veronica", "Archie", "Jughead"])

# this will set some values on some settings
what_the_hell_is_even_going_on = Riverdale()

# we can just recall the values of those settings
settings().get_value("people_that_died")
settings().get_value("kids")

Code:

import os

# https://forum.qt.io/topic/88531/singleton-in-python-with-qobject/2
try:
    from PyQt5.QtCore import pyqtWrapperType
except ImportError:
    from sip import wrappertype as pyqtWrapperType

class Singleton(pyqtWrapperType, type):
    def __init__(cls, name, bases, dict):
        super().__init__(name, bases, dict)
        cls.instance=None

    def __call__(cls,*args,**kw):
        if cls.instance is None:
            cls.instance=super().__call__(*args, **kw)
        return cls.instance



class EasySettingsBase(object):
    def __init__(self, file_location=""):
        """
        Initializer

        :param file_location: this is the location where the settings file will be saved
        """
        self.__file_location = file_location
        if os.path.isfile(self.__file_location):
            with open(file_location) as f:
                self.__settings_dictionary = json.load(f)
        else:
            self.__settings_dictionary = {}
            dirname = os.path.dirname(self.__file_location)
            if not os.path.isdir(dirname):
                os.makedirs(dirname)
            self.__save_json()

    def reset(self):
        """
        Deletes the save json file and reinitalizes, resettings all saved settings
        :return:
        """
        if os.path.isfile(self.__file_location):
            os.remove(self.__file_location)

        self.__init__(self.__file_location)
        self.__settings_dictionary = {}

    def get_file_location(self):
        """
        Gets the location of the file on disc where the settings are saved
        :return: filepath
        """
        return self.__file_location

    def setting_exists(self, settingName, dictionary=None):
        """
        Check if a setting with a certain name exists

        :param settingName: setting you're looking for
        :return: bool
        """
        if dictionary is None:
            dictionary = self.__settings_dictionary

        if settingName in dictionary:
            return True
        else:
            return False

    def value_exists(self, search_value, recursive=True, dictionary=None):
        """
        Checks if a value exists in the setting

        :param search_value: value you're looking for
        :param recursive: check whether or not the value exists in nested dictionaries
        :param dictionary: best to leave it set to None
        :return:
        """
        if dictionary is None:
            dictionary = self.__settings_dictionary

        if recursive:
            for value in dictionary.values():
                if isinstance(value, dict):
                    return self.value_exists(search_value, value)

        if value in dictionary.values():
            return True

    def get_setting_with_value(self, value):
        """
        Gets all the settings with a particular value

        :param value: value you're looking for
        :return: a list of all the setting names that match the value
        """
        values = []
        try:
            values.append(self.__settings_dictionary.keys()[self.__settings_dictionary.values().index(value)])
        except ValueError as err:
            pass

        return values

    def get_all_settings_names(self):
        """
        Gets all the settings

        :return: a list with all the settingnames
        """
        return self.__settings_dictionary.keys()

    def set_value(self, setting_name, value):
        """
        Sets the value of a setting

        :param setting_name: name of the setting you want to zet
        :param value: value of the setting
        :return: nothing
        """
        self.__settings_dictionary[setting_name] = value
        self.__save_json()

    def get_value(self, setting_name, *args):
        """
        Gets the value of the settings you're using

        :param setting_name: name of the setting you want to get
        :param args: the default value you want to load if the setting can't be found
        :return: value or default value
        """
        if args:
            return self.__settings_dictionary.get(setting_name, *args)

        return self.__settings_dictionary.get(setting_name)

    def append_value(self, setting_name, value):
        """
        Provided the setting is a list, this appends the value to the provided setting value.
        The function will raise a TypeError if settingName is a not a list

        :param setting_name: name of the setting list you want to add value to
        :param value: value you want to add
        :return: nothing
        """
        old_value = self.get_value(setting_name, [])
        if not isinstance(old_value, list):
            raise TypeError("This method expects the setting to be a list, %s is a %s" % (setting_name, type(old_value)))

        if not isinstance(value, list):
            value = [value]

        newValue = old_value + value

        self.set_value(setting_name, newValue)

    def pop_value(self, setting_name, value):
        """
        Provided the setting is a list, this removes the value to the provided setting value.
        The function will raise a TypeError if settingName is a not a list

        :param setting_name: name of the setting you want to remove the value from
        :param value: value you want to remove
        :return:
        """
        oldValue = self.get_value(setting_name, [])
        if not isinstance(oldValue, list):
            raise TypeError("This method expects the setting to be a list, %s is a %s" % (setting_name, type(oldValue)))

        if value in oldValue:
            oldValue.remove(value)
            self.set_value(setting_name, oldValue)


    def remove_setting(self, setting_name):
        """
        Removes a setting from the settings file

        :param setting_name: setting you want to remove
        :return:
        """
        self.__settings_dictionary.pop(setting_name)
        self.__save_json()

    def __save_json(self):
        with open(self.__file_location, 'w+') as outfile:
            json.dump(self.__settings_dictionary, outfile, indent=4)


class EasySettingsSingleton(EasySettingsBase, metaclass=Singleton):
    def __init__(self, file_location=""):
        super().__init__(file_location)