Esempio n. 1
0
def test_ffapi_push():
    f = FFApi(deepcopy(A))
    assert f.push(None) is None
    assert f.c == A

    assert f.push({'x': 'y'}, 'a', 'b') is None
    A['a']['b'] = {'x': 'y'}

    assert f.push(1337, 'a', 'd') is None
    A['a']['d'] = 1337

    assert f.push([23, 42], 'g') is None
    A['g'] = [23, 42]

    assert f.push('test', 'i', 'j') is None
    A['i']['j'] = 'test'

    assert f.c == A
Esempio n. 2
0
def test_ffapi_push():
    f = FFApi(deepcopy(A))
    assert f.push(None) is None
    assert f.c == A

    assert f.push({'x': 'y'}, 'a', 'b') is None
    A['a']['b'] = {'x': 'y'}

    assert f.push(1337, 'a', 'd') is None
    A['a']['d'] = 1337

    assert f.push([23, 42], 'g') is None
    A['g'] = [23, 42]

    assert f.push('test', 'i', 'j') is None
    A['i']['j'] = 'test'

    assert f.c == A
Esempio n. 3
0
class FFFlash:
    '''
    This is the main object, which stores all relevant information,
    and the :class:`ffflash.lib.api.FFApi` itself.

    :param args: ``Namespace`` object from :meth:`ffflash.lib.args.parsed_args`
    '''
    def __init__(self, args):
        self.args = args
        self.location = check_file_location(self.args.APIfile, must_exist=True)
        self.api = None

        self.load_api()

    def load_api(self):
        '''
        Populate :attr:`api` with :class:`ffflash.lib.api.FFApi` with content
        loaded from :attr:`location`.

        :attr:`api` is populated only once, this prevents accidental reloads.
        '''
        if (self.api is None) and self.location:
            c = load_file(self.location, as_yaml=False)
            if c:
                self.api = FFApi(c)

    def set_timestamp(self):
        '''
        Inject :meth:`ffflash.lib.clock.get_iso_timestamp`
        into ``state.lastchange``.
        '''
        if self.access_for('api'):
            if self.api.pull('state', 'lastchange') is not None:
                self.api.push(get_iso_timestamp(), 'state', 'lastchange')

    def save(self):
        '''
        Save content from :attr:`api` (:class:`ffflash.lib.api.FFApi`) into
        :attr:`location`.
        A :meth:`ffflash.lib.api.FFApi.timestamp` is triggered before saving.
        '''
        if self.access_for('api'):
            self.set_timestamp()
            return dump_file(self.location, self.api.c, as_yaml=False)

    def access_for(self, name):
        '''
        Check if it is save to access the api and/or depending files.

        :param name: String specifier of part to access.
        :return: ``True`` or ``False``
        '''
        return all([(self.api is not None), {
            'api': self.location,
            'sidecars': self.args.sidecars,
            'nodelist': self.args.nodelist,
            'rankfile': all([self.args.nodelist, self.args.rankfile]),
        }.get(name, False)])

    def log(self, message, level=True):
        '''
        Very advanced Logger. For professional use only.

        :param message: Some message string to display
        :param level: Severity of message. Can be anything as this is also the
            return value. There are three predefined rules:

            * ``True``: *info* (is dismissed unless ``--verbose`` was given)
            * ``None``: *warn*
            * ``False``: *error*
        :return: ``level``
        '''
        c = {
            True: 'info',
            None: 'warn',
            False: 'error'
        }.get(level, level) if (level is None
                                or isinstance(level,
                                              (bool, str))) else 'output'

        if self.args.verbose or level is not True:
            print('{}\t{}'.format(c.upper(), message))
        return level
Esempio n. 4
0
class FFFlash:
    '''
    This is the main object, which stores all relevant information,
    and the :class:`ffflash.lib.api.FFApi` itself.

    :param args: ``Namespace`` object from :meth:`ffflash.lib.args.parsed_args`
    '''
    def __init__(self, args):
        self.args = args
        self.location = check_file_location(self.args.APIfile, must_exist=True)
        self.api = None

        self.load_api()

    def load_api(self):
        '''
        Populate :attr:`api` with :class:`ffflash.lib.api.FFApi` with content
        loaded from :attr:`location`.

        :attr:`api` is populated only once, this prevents accidental reloads.
        '''
        if (self.api is None) and self.location:
            c = load_file(self.location, as_yaml=False)
            if c:
                self.api = FFApi(c)

    def set_timestamp(self):
        '''
        Inject :meth:`ffflash.lib.clock.get_iso_timestamp`
        into ``state.lastchange``.
        '''
        if self.access_for('api'):
            if self.api.pull('state', 'lastchange') is not None:
                self.api.push(get_iso_timestamp(), 'state', 'lastchange')

    def save(self):
        '''
        Save content from :attr:`api` (:class:`ffflash.lib.api.FFApi`) into
        :attr:`location`.
        A :meth:`ffflash.lib.api.FFApi.timestamp` is triggered before saving.
        '''
        if self.access_for('api'):
            self.set_timestamp()
            return dump_file(self.location, self.api.c, as_yaml=False)

    def access_for(self, name):
        '''
        Check if it is save to access the api and/or depending files.

        :param name: String specifier of part to access.
        :return: ``True`` or ``False``
        '''
        return all([
            (self.api is not None),
            {
                'api': self.location,
                'sidecars': self.args.sidecars,
                'nodelist': self.args.nodelist,
                'rankfile': all([
                    self.args.nodelist, self.args.rankfile
                ]),
            }.get(name, False)
        ])

    def log(self, message, level=True):
        '''
        Very advanced Logger. For professional use only.

        :param message: Some message string to display
        :param level: Severity of message. Can be anything as this is also the
            return value. There are three predefined rules:

            * ``True``: *info* (is dismissed unless ``--verbose`` was given)
            * ``None``: *warn*
            * ``False``: *error*
        :return: ``level``
        '''
        c = {
            True: 'info', None: 'warn', False: 'error'
        }.get(level, level) if (
            level is None or isinstance(level, (bool, str))
        ) else 'output'

        if self.args.verbose or level is not True:
            print('{}\t{}'.format(c.upper(), message))
        return level