Source code for photon.meta

from random import randint as _randint
from threading import Lock

from photon import IDENT

from photon.util.files import read_json, write_json
from photon.util.locations import search_location
from photon.util.structures import dict_merge
from photon.util.system import get_timestamp, shell_notify


[docs]class Meta(object): ''' Meta is a class which bounds to an actual json-file on disk. It provides a logger storing the entries in that json-file. It is also possible to import contents. By staging out to a different directory meta-files are left behind for further debugging or to see what was going on. :param meta: Initial, clean meta file to use. See :meth:`stage` for more :param verbose: Sets the `verbose` flag for the underlying :ref:`util` functions ''' def __init__(self, meta='meta.json', verbose=True): super().__init__() self.__verbose = verbose self.__meta = { 'header': { 'ident': '%s-%4X' % (IDENT, _randint(0x1000, 0xffff)), 'initialized': get_timestamp(), 'verbose': verbose }, 'import': dict(), 'log': dict() } self.__lock = Lock() self.stage(meta, clean=True)
[docs] def stage(self, name, clean=False): ''' Switch stage :param name: Filename of new meta file. |filelocate| * File must not already exist, will be created in 'data_dir' \ from :func:`util.locations.get_locations` * Can also be a full path to place it anywhere desired :param clean: What to do with preexisting meta files? * ``False``: Merge current meta with preexisting one * ``True``: Replace preexisting meta with current one ''' name = search_location(name, create_in='data_dir') if not clean: self.load('stage', name, merge=True) self.__meta['header'].update({'stage': name}) self.log = shell_notify( '%s stage' % ('new clean' if clean else 'loaded'), more=dict(meta=name, clean=clean), verbose=self.__verbose )
[docs] def load(self, mkey, mdesc, mdict=None, merge=False): ''' Loads a dictionary into current meta :param mkey: Type of data to load. Is be used to reference the data from the 'header' within meta :param mdesc: Either filename of json-file to load or further description of imported data when `mdict` is used :param dict mdict: Directly pass data as dictionary instead of loading it from a json-file. Make sure to set `mkey` and `mdesc` accordingly :param merge: Merge received data into current meta or place it under 'import' within meta :returns: The loaded (or directly passed) content ''' j = mdict if mdict else read_json(mdesc) if j and isinstance(j, dict): self.__meta['header'].update({mkey: mdesc}) if merge: self.__meta = dict_merge(self.__meta, j) else: self.__meta['import'][mkey] = j self.log = shell_notify( 'load %s data and %s it into meta' % ( 'got' if mdict else 'read', 'merged' if merge else 'imported' ), more=dict(mkey=mkey, mdesc=mdesc, merge=merge), verbose=self.__verbose ) return j
@property def log(self): ''' :param elem: Add a new log entry to the meta. * Can be anything. * The log is a dictionary with keys \ generated from the output of :func:`util.system.get_timestamp` \ and `elem` as value :returns: Current meta ''' return self.__meta @log.setter def log(self, elem): ''' .. seealso:: :attr:`log` ''' if elem: self.__meta['log'].update({get_timestamp(precice=True): elem}) mfile = self.__meta['header']['stage'] self.__lock.acquire() try: j = read_json(mfile) if j != self.__meta: write_json(mfile, self.__meta) finally: self.__lock.release()