def repr_settings(settings: QSettings) -> str: """works on a QSettings, not a Settings""" msg = 'QSettings:\n' for key in sorted(settings.allKeys()): value = settings.value(key) msg += ' %r : %r\n' % (key, value) return msg
def restore_from_defaults(): """ Clears all settings (except "defaults" group) and restores all settings from the defaults group. """ settings = QSettings() for g in settings.childGroups(): if g != "defaults": settings.remove(g) for k in settings.childKeys(): settings.remove(k) defaults = QSettings() defaults.beginGroup("defaults") for k in defaults.allKeys(): settings.setValue(k, defaults.value(k))
class UserConfig(object): """Holds user configuration option. Options are assigned a section and a key must only be unique within a section. Uses QSettings for the heavy lifting. All platforms use the Ini format at UserScope """ # The raw QSettings instance qsettings = None defaults = None def __init__(self, organization, application, defaults=None): """ :param organization: A string name for the organization :param application: A string name for the application name :param defaults: Default configuration values for this instance in the form of nested dict instances """ # Loads the saved settings if found self.qsettings = QSettings(QSettings.IniFormat, QSettings.UserScope, organization, application) self.defaults = defaults def all_keys(self): return self.qsettings.allKeys() @property def filename(self): return self.qsettings.fileName() def get(self, section, option): """ Return a value for an option in a given section. If not specified in the saved settings then the initial defaults are consulted. If no option is found then a KeyError is raised :param section: A string section name :param option: A string option name :return: The value of the option """ value = self.qsettings.value(self._settings_path(section, option)) if not value: value = self._get_default_or_raise(section, option) return value def set(self, section, option, value): """ Set a value for an option in a given section. :param section: A string section name :param option: A string option name :param value: The value of the setting """ self.qsettings.setValue(self._settings_path(section, option), value) # ------------------------------------------------------------------------- # "Private" methods # ------------------------------------------------------------------------- def _check_section_option_is_valid(self, section, option): """ Sanity check the section and option are strings """ if not is_text_string(section): raise RuntimeError("section is not a text string") if not is_text_string(option): raise RuntimeError("option is not a text string") def _get_default_or_raise(self, section, option): """ Returns the value listed in the defaults if it exists :param section: A string denoting the section (not checked) :param option: A string denoting the option name :return: The value of the default :raises KeyError: if the item does not exist """ value = None if self.defaults and section in self.defaults: try: value = self.defaults[section][option] except KeyError: raise KeyError("Unknown config item requested: " + self._settings_path(section, option)) return value def _settings_path(self, section, option): """ Private method to construct a path to the given option with the section :param section: The name of the section :param option: The name of the option :return: A path to the location within the QSettings instance """ self._check_section_option_is_valid(section, option) return section + "/" + option
class UserConfig(object): """Holds user configuration option. Options are assigned a section and a key must only be unique within a section. Uses QSettings for the heavy lifting. All platforms use the Ini format at UserScope """ # The raw QSettings instance qsettings = None def __init__(self, organization, application, defaults=None): """ :param organization: A string name for the organization :param application: A string name for the application name :param defaults: Default configuration values for this instance in the form of nested dict instances """ # Loads the saved settings if found self.qsettings = QSettings(QSettings.IniFormat, QSettings.UserScope, organization, application) # convert the defaults into something that qsettings can handle default_settings = self._flatten_defaults(defaults) # put defaults into qsettings if they weren't there already try: self.set_qsettings_values(default_settings) # the editors/sessiontabs are pickled in config so need to remove them except ValueError: self.qsettings.remove('Editors/SessionTabs') self.set_qsettings_values(default_settings) def set_qsettings_values(self, default_settings): configFileKeys = self.qsettings.allKeys() for key in default_settings.keys(): if key not in configFileKeys: self.qsettings.setValue(key, default_settings[key]) def all_keys(self, group=None): if group is not None: self.qsettings.beginGroup(group) result = self.qsettings.allKeys() self.qsettings.endGroup() else: result = self.qsettings.allKeys() return result @property def filename(self): return self.qsettings.fileName() def get(self, option, second=None, type=None): """Return a value for an option. If two arguments are given the first is the group/section and the second is the option within it. ``config.get('main', 'window/size')`` is equivalent to ``config.get('main/window/size')`` If no option is found then a KeyError is raised """ try: return self._get_setting(option, second, type) except TypeError: # The 'PyQt_PyObject' (1024) type is sometimes used for settings which have an unknown type. value = self._get_setting(option, second, type=QVariant.typeToName(1024)) return value if isinstance(value, type) else type(*value) def has(self, option, second=None): """Return a True if the key exists in the settings. ``config.get('main', 'window/size')`` and ``config.get('main/window/size')`` are equivalent. """ option = self._check_section_option_is_valid(option, second) return option in self.all_keys() def set(self, option, value, extra=None): """Set a value for an option in a given section. Can either supply the fully qualified option or add the section as an additional first argument. ``config.set('main', 'high_dpi_scaling', True)`` is equivalent to ``config.set('main/high_dpi_scaling', True)`` """ if extra is None: option = self._check_section_option_is_valid(option, extra) # value is in the right place else: option = self._check_section_option_is_valid(option, value) value = extra self.qsettings.setValue(option, value) def remove(self, option, second=None): """Removes a key from the settings. Key not existing returns without effect. """ option = self._check_section_option_is_valid(option, second) if self.has(option): self.qsettings.remove(option) # ------------------------------------------------------------------------- # "Private" methods # ------------------------------------------------------------------------- @staticmethod def _flatten_defaults(input_dict): result = {} for key in input_dict: value = input_dict[key] if isinstance(value, dict): value = UserConfig._flatten_defaults(value) for key_inner in value.keys(): result[joinsettings(key, key_inner)] = value[key_inner] else: result[key] = value return result def _check_section_option_is_valid(self, option, second): """ Sanity check the section and option are strings and return the flattened option key """ if second is None: if not isinstance(option, str): raise TypeError( 'Found invalid type ({}) for option ({}) must be a string'. format(type(option), option)) return option else: # first argument is actually the section/group if not isinstance(option, str): raise TypeError( 'Found invalid type ({}) for section ({}) must be a string' .format(type(option), option)) if not isinstance(second, str): raise TypeError( 'Found invalid type ({}) for option ({}) must be a string'. format(type(second), second)) return joinsettings(option, second) def _get_setting(self, option, second=None, type=None): """Return a value for an option. If two arguments are given the first is the group/section and the second is the option within it. ``config.get('main', 'window/size')`` is equivalent to ``config.get('main/window/size')`` If no option is found then a KeyError is raised """ full_option = self._check_section_option_is_valid(option, second) if type is None: # Some platforms only ever store string values in QSettings so the type of stored settings can get lost raise ValueError( "Please specify the type of the setting you are retrieving.") if not self.has(option, second): # If a setting does not exist, we want to raise a KeyError raise KeyError(f"Unknown config item requested: '{option}'") return self.qsettings.value(full_option, type=type)
def __iter__(self): settings = QSettings(parent=self.parent) settings.beginGroup(self.group) keys = settings.allKeys() for k in keys: yield k, settings.value(k)
class UserConfig(object): """Holds user configuration option. Options are assigned a section and a key must only be unique within a section. Uses QSettings for the heavy lifting. All platforms use the Ini format at UserScope """ # The raw QSettings instance qsettings = None def __init__(self, organization, application, defaults=None): """ :param organization: A string name for the organization :param application: A string name for the application name :param defaults: Default configuration values for this instance in the form of nested dict instances """ # Loads the saved settings if found self.qsettings = QSettings(QSettings.IniFormat, QSettings.UserScope, organization, application) # convert the defaults into something that qsettings can handle default_settings = self._flatten_defaults(defaults) # put defaults into qsettings if they weren't there already try: self.set_qsettings_values(default_settings) # the editors/sessiontabs are pickled in config so need to remove them except ValueError: self.qsettings.remove('Editors/SessionTabs') self.set_qsettings_values(default_settings) # fixup the values of booleans - they do not evaluate correctly when read from the config file for key in self.all_keys(): try: value = self.get(key) except (KeyError, TypeError): continue if value == 'true': self.set(key, True) elif value == 'false': self.set(key, False) def set_qsettings_values(self, default_settings): configFileKeys = self.qsettings.allKeys() for key in default_settings.keys(): if key not in configFileKeys: self.qsettings.setValue(key, default_settings[key]) def all_keys(self, group=None): if group is not None: self.qsettings.beginGroup(group) result = self.qsettings.allKeys() self.qsettings.endGroup() else: result = self.qsettings.allKeys() return result @property def filename(self): return self.qsettings.fileName() def get(self, option, second=None, type=None): """Return a value for an option. If two arguments are given the first is the group/section and the second is the option within it. ``config.get('main', 'window/size')`` is equivalent to ``config.get('main/window/size')`` If no option is found then a KeyError is raised """ def raise_keyerror(key): raise KeyError( 'Unknown config item requested: "{}"'.format(option)) full_option = self._check_section_option_is_valid(option, second) if type is None: # return whatever the QSettings object returns value = self.qsettings.value(full_option) if value is None: raise_keyerror(full_option) else: return value else: # PyQt QSettings with the type parameter tries to always return the type even if no value exists # We still want a KeyError if it does not exist if self.has(option, second): return self.qsettings.value(full_option, type=type) else: raise_keyerror(option) def has(self, option, second=None): """Return a True if the key exists in the settings. ``config.get('main', 'window/size')`` and ``config.get('main/window/size')`` are equivalent. """ option = self._check_section_option_is_valid(option, second) return option in self.all_keys() def set(self, option, value, extra=None): """Set a value for an option in a given section. Can either supply the fully qualified option or add the section as an additional first argument. ``config.set('main', 'high_dpi_scaling', True)`` is equivalent to ``config.set('main/high_dpi_scaling', True)`` """ if extra is None: option = self._check_section_option_is_valid(option, extra) # value is in the right place else: option = self._check_section_option_is_valid(option, value) value = extra self.qsettings.setValue(option, value) def remove(self, option, second=None): """Removes a key from the settings. Key not existing returns without effect. """ option = self._check_section_option_is_valid(option, second) if self.has(option): self.qsettings.remove(option) # ------------------------------------------------------------------------- # "Private" methods # ------------------------------------------------------------------------- @staticmethod def _flatten_defaults(input_dict): result = {} for key in input_dict: value = input_dict[key] if isinstance(value, dict): value = UserConfig._flatten_defaults(value) for key_inner in value.keys(): result[joinsettings(key, key_inner)] = value[key_inner] else: result[key] = value return result def _check_section_option_is_valid(self, option, second): """ Sanity check the section and option are strings and return the flattened option key """ if second is None: if not isinstance(option, str): raise TypeError( 'Found invalid type ({}) for option ({}) must be a string'. format(type(option), option)) return option else: # first argument is actually the section/group if not isinstance(option, str): raise TypeError( 'Found invalid type ({}) for section ({}) must be a string' .format(type(option), option)) if not isinstance(second, str): raise TypeError( 'Found invalid type ({}) for option ({}) must be a string'. format(type(second), second)) return joinsettings(option, second)
class UserConfig(object): """Holds user configuration option. Options are assigned a section and a key must only be unique within a section. Uses QSettings for the heavy lifting. All platforms use the Ini format at UserScope """ # The raw QSettings instance qsettings = None def __init__(self, organization, application, defaults=None): """ :param organization: A string name for the organization :param application: A string name for the application name :param defaults: Default configuration values for this instance in the form of nested dict instances """ # Loads the saved settings if found self.qsettings = QSettings(QSettings.IniFormat, QSettings.UserScope, organization, application) # convert the defaults into something that qsettings can handle default_settings = self._flatten_defaults(defaults) # put defaults into qsettings if they weren't there already try: self.set_qsettings_values(default_settings) # the editors/sessiontabs are pickled in config so need to remove them except ValueError: self.qsettings.remove('Editors/SessionTabs') self.set_qsettings_values(default_settings) # fixup the values of booleans - they do not evaluate correctly when read from the config file for key in self.all_keys(): try: value = self.get(key) except KeyError: continue if value == 'true': self.set(key, True) elif value == 'false': self.set(key, False) def set_qsettings_values(self, default_settings): configFileKeys = self.qsettings.allKeys() for key in default_settings.keys(): if key not in configFileKeys: self.qsettings.setValue(key, default_settings[key]) def all_keys(self, group=None): if group is not None: self.qsettings.beginGroup(group) result = self.qsettings.allKeys() self.qsettings.endGroup() else: result = self.qsettings.allKeys() return result @property def filename(self): return self.qsettings.fileName() def get(self, option, second=None): """Return a value for an option. If two arguments are given the first is the group/section and the second is the option within it. ``config.get('main', 'window/size')`` is equivalent to ``config.get('main/window/size')`` If no option is found then a KeyError is raised """ option = self._check_section_option_is_valid(option, second) value = self.qsettings.value(option) # qsettings appears to return None if the option isn't found if value is None: raise KeyError('Unknown config item requested: "{}"'.format(option)) else: return value def has(self, option, second=None): """Return a True if the key exists in the settings. ``config.get('main', 'window/size')`` and ``config.get('main/window/size')`` are equivalent. """ option = self._check_section_option_is_valid(option, second) return option in self.all_keys() def set(self, option, value, extra=None): """Set a value for an option in a given section. Can either supply the fully qualified option or add the section as an additional first argument. ``config.set('main', 'high_dpi_scaling', True)`` is equivalent to ``config.set('main/high_dpi_scaling', True)`` """ if extra is None: option = self._check_section_option_is_valid(option, extra) # value is in the right place else: option = self._check_section_option_is_valid(option, value) value = extra self.qsettings.setValue(option, value) def remove(self, option, second=None): """Removes a key from the settings. Key not existing returns without effect. """ option = self._check_section_option_is_valid(option, second) if self.has(option): self.qsettings.remove(option) # ------------------------------------------------------------------------- # "Private" methods # ------------------------------------------------------------------------- @staticmethod def _flatten_defaults(input_dict): result = {} for key in input_dict: value = input_dict[key] if isinstance(value, dict): value = UserConfig._flatten_defaults(value) for key_inner in value.keys(): result[joinsettings(key, key_inner)] = value[key_inner] else: result[key] = value return result def _check_section_option_is_valid(self, option, second): """ Sanity check the section and option are strings and return the flattened option key """ if second is None: if not is_text_string(option): raise TypeError('Found invalid type ({}) for option ({}) must be a string'.format(type(option), option)) return option else: # fist argument is actually the section/group if not is_text_string(option): raise TypeError('Found invalid type ({}) for section ({}) must be a string'.format(type(option), option)) if not is_text_string(second): raise TypeError('Found invalid type ({}) for option ({}) must be a string'.format(type(second), second)) return joinsettings(option, second)