Source code for puzzlestream.backend.config

# -*- coding: utf-8 -*-
"""Configuration module.

contains PSConfig
"""

import json
import locale
import os
from threading import Thread

from appdirs import user_config_dir
from puzzlestream.backend.signal import PSSignal

locale.setlocale(locale.LC_ALL, "")


[docs]class PSConfig(dict): """Configuration class. This class holds all general Puzzlestream configuration settings. One configuration object per Puzzlestream instance is intended. Settings are saved in the user_config_dir (provided by appdirs) automatically as a json file when a setting is changed. """ def __init__(self, *args): """Initialise directory and update event. All args are passed to the dictionary super class. """ super().__init__(*args) self.__configDir = user_config_dir("Puzzlestream") self.__edited = PSSignal() self.load() def __setitem__(self, key: str, value: object, save: bool = True): """Emit update event on item set, autosave. Args: key (str): Configuration key. value (:obj:): Value the setting `key` shall be set to. save (bool): Whether the configuration should be saved immediately. Default: True. """ super().__setitem__(key, value) self.edited.emit(key) if save: self.save() def __setDefaultItem(self, key, value): """Set setting `key` to `value` if setting does not yet exist. Args: key (str): Configuration key. value (:obj:): Default value that `key` setting is set to. """ if key not in self: super().__setitem__(key, value) self.edited.emit(key) @property def edited(self) -> PSSignal: """Edit signal that is emitted when a config value changes.""" return self.__edited
[docs] def save(self): """Run save thread in background. The background thread creates the user_config_dir if necessary and dumps the config as a json file. """ Thread(target=self.__save).start()
def __save(self): """Create user_config_dir if necessary and dump config as json file.""" if not os.path.isdir(self.__configDir): os.makedirs(self.__configDir) with open(self.__configDir + "/config.json", "w") as f: json.dump(self, f)
[docs] def load(self): """Load config from file if the file exists and set default values.""" if os.path.isfile(self.__configDir + "/config.json"): try: with open(self.__configDir + "/config.json", "r") as f: self.clear() self.update(json.load(f)) except Exception as e: print(e) self.__setDefaults()
def __setDefaults(self): """Set configuration values to their defaults if they don't exist.""" if locale.getlocale()[0][:2] == "de": ind_lang = 1 else: ind_lang = 0 self.__setDefaultItem("language", [ind_lang, ["English", "Deutsch"]]) self.__setDefaultItem("last projects", []) self.__setDefaultItem("autotilePlots", True) self.__setDefaultItem("numberOfProcesses", 0) self.__setDefaultItem("autoformatOnSave", True) self.__setDefaultItem("saveOnRun", True) self.__setDefaultItem("saveOnEditorFocusOut", True) self.__setDefaultItem("clockOnlyFullscreen", True) self.__setDefaultItem("design", [0, ["dark", "light"]]) self.__setDefaultItem("puzzleZoom", 10) self.__setDefaultItem("slowerRedraw", False) self.__setDefaultItem("libs", []) # self.__setDefaultItem("Test", True) # self.__setDefaultItem("Test 2", "bla") # self.__setDefaultItem("Test 3", [0, ["0", "1", "2"]]) self.translations = { "numberOfProcesses": "Number of concurrent processes\n(0 = " + "number of CPU cores, recommended)", "autoformatOnSave": "Autoformat on save", "language": "Language", "clockOnlyFullscreen": "Show clock only when in full screen", "saveOnRun": "Save before running modules", "saveOnEditorFocusOut": "Save when editor loses focus", "design": "Design", "slowerRedraw": "Slower drawing (activate if the\npuzzle view is not " + "redrawn correctly)" }
[docs] def addRecentProject(self, path): """Add `path` to recently used projects.""" if path in self["last projects"]: i = self["last projects"].index(path) del self["last projects"][i] self["last projects"].append(path) if len(self["last projects"]) > 10: del self["last projects"][0] self.edited.emit("last projects") self.save()