Source code for ccpn.framework.Preferences

"""
This file contains the Preference object and related methods;
"""
#=========================================================================================
# Licence, Reference and Credits
#=========================================================================================
__copyright__ = "Copyright (C) CCPN project (https://www.ccpn.ac.uk) 2014 - 2022"
__credits__ = ("Ed Brooksbank, Joanna Fox, Victoria A Higman, Luca Mureddu, Eliza Płoskoń",
               "Timothy J Ragan, Brian O Smith, Gary S Thompson & Geerten W Vuister")
__licence__ = ("CCPN licence. See https://ccpn.ac.uk/software/licensing/")
__reference__ = ("Skinner, S.P., Fogh, R.H., Boucher, W., Ragan, T.J., Mureddu, L.G., & Vuister, G.W.",
                 "CcpNmr AnalysisAssign: a flexible platform for integrated NMR analysis",
                 "J.Biomol.Nmr (2016), 66, 111-124, http://doi.org/10.1007/s10858-016-0060-y")
#=========================================================================================
# Last code modification
#=========================================================================================
__modifiedBy__ = "$modifiedBy: Ed Brooksbank $"
__dateModified__ = "$dateModified: 2022-03-09 17:07:32 +0000 (Wed, March 09, 2022) $"
__version__ = "$Revision: 3.1.0 $"
#=========================================================================================
# Created
#=========================================================================================
__author__ = "$Author: gvuister $"
__date__ = "$Date: 2022-01-18 10:28:48 +0000 (Tue, January 18, 2022) $"
#=========================================================================================
# Start of code
#=========================================================================================

import json

from ccpn.util.AttrDict import AttrDict
from ccpn.util.decorators import singleton
from ccpn.util.Path import aPath
from ccpn.util.Common import uniquify

from ccpn.framework.PathsAndUrls import \
    userPreferencesPath, \
    userPreferencesDirectory, \
    defaultPreferencesPath

from ccpn.framework.Application import getApplication


ARIA_PATH = 'externalPrograms.aria'
CYANA_PATH = 'externalPrograms.cyana'
XPLOR_NIH_PATH = 'externalPrograms.xplor'
TALOS_PATH = 'externalPrograms.talos'
PYMOL_PATH = 'externalPrograms.pymol'

USER_DATA_PATH = 'general.dataPath'
USER_MACRO_PATH = 'general.userMacroPath'
USER_PLUGIN_PATH = 'general.userPluginPath'
USER_PIPES_PATH = 'general.userPipesPath'
USER_LAYOUTS_PATH = 'general.userLayoutsPath'

PRINT_OPTIONS = 'printSettings.printOptions'

USE_PROJECT_PATH = 'general.useProjectPath'


[docs]def getPreferences(): """Return the Preferences instance""" if (app := getApplication()) is None: raise RuntimeError('getPreferences: application has not registered itself!') return app.preferences
[docs]@singleton class Preferences(AttrDict): """A singleton class to hold the preferences, implemented as a AttrDict-of-AttrDict-of-AttrDict """ def __init__(self, application): super().__init__() self._applicationVersion = str(application.applicationVersion) self._lastPath = None if not userPreferencesDirectory.exists(): userPreferencesDirectory.mkdir() # read the default preference and populate self so all valid keys # are defined if not (_prefs := self._readPreferencesFile(defaultPreferencesPath)): raise ValueError(f'Preferences._readPreferences: path {defaultPreferencesPath} does not exist') self.update(_prefs) def _readPreferencesFile(self, path): """Read the preference from the json file path, :return the json encoded preferences object """ path = aPath(path) if not path.exists(): return None with path.open(mode='r') as fp: _prefs = json.load(fp, object_hook=AttrDict) self._lastPath = str(path) return _prefs def _getUserPreferences(self): """Read the user preferences file, updating the current values """ if (_prefs := self._readPreferencesFile(userPreferencesPath)): self._recursiveUpdate(theDict=self, updateDict=_prefs) # just some patches to the data self.recentMacros = uniquify(self.recentMacros) def _saveUserPreferences(self): """Save the current preferences to the user preferences file """ with userPreferencesPath.open(mode='w') as fp: json.dump(self, fp, indent=4) def _recursiveUpdate(self, theDict, updateDict): """update theDict with key,value from updateDict, if key exists in theDict Recursively update, by expanding any dict-like value first """ if not isinstance(theDict, (dict, AttrDict)): raise ValueError(f'Preferences._recursiveUpdate: invalid dict {theDict}') if not isinstance(updateDict, (dict, AttrDict)): raise ValueError(f'Preferences._recursiveUpdate: invalid updateDict {updateDict}') for key, value in theDict.items(): # check and update for any keys in theDict that are in updateDict if key in updateDict: updateValue = updateDict[key] if isinstance(value, (dict, AttrDict)): self._recursiveUpdate(value, updateValue) else: theDict[key] = updateValue dashes = '-' * 5 def _recursivePrint(self, theDict, keys=None): """print (key, value) of theDict, recursively expanding key for dict-like value's """ if keys is None: keys = [] for key, value in theDict.items(): _keys = keys[:] + [key] if isinstance(value, AttrDict) and len(_keys) < 2: self._recursivePrint(value, keys=_keys) else: _keyStr = '.'.join(_keys) print(f'{_keyStr:40} : {repr(value)}')
[docs] def get(self, key, default=None): """Return the value for key if key is in the dictionary, else default. Check for key to be a "dotted" one; e.g. "aap.noot" If so, recusively decent. """ if key is None or not isinstance(key, str) or len(key) == 0: raise KeyError(f'invalid key {repr(key)}') _keys = key.split('.') _value = AttrDict.get(self, _keys[0], default) if _value is None or \ len(_keys) == 1 or \ len(_keys) > 1 and len(_keys[1]) == 0: return _value elif isinstance(_value, (dict, AttrDict)): # Re return Preferences.get(_value, '.'.join(_keys[1:]), default=default) else: raise KeyError(f'invalid key {repr(key)}; unable to decode')
[docs] def print(self): """Print items of self """ print(self.dashes, self, self.dashes) self._recursivePrint(self)
def __str__(self): return f'<Preferences: {repr(self._lastPath)}>'