Source code for photon.settings

'''
.. |yaml_loaders| replace:: :func:`util.structures.yaml_str_join`
    and :func:`util.structures.yaml_loc_join`
'''

from photon.util.files import read_yaml, write_yaml
from photon.util.locations import get_locations, search_location
from photon.util.structures import dict_merge, yaml_loc_join, yaml_str_join
from photon.util.system import shell_notify


[docs]class Settings(object): ''' Settings is a class which provides access to compiled settings loaded from YAML-files. The YAML-files will be read with specific loaders which enables certain logic within the configuration. It is possible to: * Insert references to existing fields via \ anchors and ``!str_join`` or ``!loc_join`` * Insert keywords like **hostname** or \ **timestamp** using ``!str_join`` * Combine path-segments using ``!loc_join`` * Insert keywords like **home_dir** or \ **conf_dir** using ``!loc_join`` It is also possible to import or merge further content. :param defaults: The initial configuration to load. |filelocate| * The common way is to use a short-filename to locate it next \ to the script using Photon. * Can also be a full path. * Can also passed directly as a dict * Bring your own defaults! |appteardown| if not found or none passed. :param config: Where to store the loaded output from the `defaults`. |filelocate| * File must already exist, will be created in 'conf_dir' \ from :func:`util.locations.get_locations` otherwise * Therefore use a short name (or full path) if one \ should be created .. note:: The last loaded file wins * The config is intended to provide a editable file \ for the end-user * If a value differs from the original values in \ `defaults`, the value in `config` wins * Other values which not exist in `config` \ will be set from `defaults` * If a value in `config` contains a loader call \ which expresses the same as the value in `defaults` \ it will be skipped. * Be careful using **timestamp** s in a config. \ The timestamp of the first launch will always be used. * Simply delete all lines within the config to completely \ reset it to the defaults * Can be skipped by explicitly setting it to ``None`` :param verbose: Sets the `verbose` flag for \ the underlying :ref:`util` functions .. seealso:: |yaml_loaders| as well as the :ref:`settings_file_example` ''' def __init__(self, defaults, config='config.yaml', verbose=True): super().__init__() self.__verbose = verbose self.__settings = { 'locations': get_locations(), 'files': dict() } loaders = [ ('!str_join', yaml_str_join,), ('!loc_join', yaml_loc_join,) ] defaults, sdict = ( 'startup import', defaults ) if isinstance(defaults, dict) else ( search_location(defaults), None ) if not self.load( 'defaults', defaults, sdict=sdict, loaders=loaders, merge=True ): shell_notify( 'could not load defaults', state=True, more=dict(defaults=defaults, sdict=sdict) ) if config: config = search_location(config, create_in='conf_dir') if self.__settings != self.load( 'config', config, loaders=loaders, merge=True, writeback=True ): shell_notify( 'settings config written', more=config, verbose=verbose )
[docs] def load(self, skey, sdesc, sdict=None, loaders=None, merge=False, writeback=False): ''' Loads a dictionary into current settings :param skey: Type of data to load. Is be used to reference the data \ in the files sections within settings :param sdesc: Either filename of yaml-file to load or further description of \ imported data when `sdict` is used :param dict sdict: Directly pass data as dictionary instead of loading \ it from a yaml-file. \ Make sure to set `skey` and `sdesc` accordingly :param list loaders: Append custom loaders to the YAML-loader. :param merge: Merge received data into current settings or \ place it under `skey` within meta :param writeback: Write back loaded (and merged/imported) result back \ to the original file. \ This is used to generate the summary files :returns: The loaded (or directly passed) content .. seealso:: |yaml_loaders| ''' y = sdict if sdict else read_yaml(sdesc, add_constructor=loaders) if y and isinstance(y, dict): if not sdict: self.__settings['files'].update({skey: sdesc}) if merge: self.__settings = dict_merge(self.__settings, y) else: self.__settings[skey] = y shell_notify( 'load %s data and %s it into settings' % ( 'got' if sdict else 'read', 'merged' if merge else 'imported' ), more=dict(skey=skey, sdesc=sdesc, merge=merge, writeback=writeback), verbose=self.__verbose ) if writeback and y != self.__settings: write_yaml(sdesc, self.__settings) return y
@property def get(self): ''' :returns: Current settings ''' return self.__settings