MultiState#

class pycraf.utils.MultiState[source]#

Bases: object

Multi state subclasses are used to manage global items.

MultiState is a so-called Singleton, which means that no instances can be created. This way, it is guaranteed that only one MultiState entity exists. Thus it offers the possibilty to handle a “global” state, because from anywhere in the code, one could query the current state and react to it. One usecase would be to temporarily allow downloading of files, otherwise being forbidden.

The MultiState class is not useful on its own, but you have to subclass it:

>>> from pycraf.utils import MultiState
>>> class MyState(MultiState):
...
...     # define list of allowed attributes
...     _attributes = ('foo', 'bar')
...
...     # set default values
...     foo = 1
...     bar = "guido"

It is mandatory to provide a tuple of allowed attributes and to create these instance attributes and assign default values. During class creation, this will be validated, for convenience.

After defining the state class, one can do the following:

>>> MyState.foo
1
>>> MyState.set(foo=2)
<MultiState MyState>
>>> MyState.foo
2

The set method returns a context manager,:

>>> with MyState.set(foo="dave", bar=10):
...     print(MyState.foo, MyState.bar)
dave 10

>>> print(MyState.foo, MyState.bar)
2 guido

which makes it possible to temporarily change the state object and go back to the original value, once the with scope has ended.

Note, that one cannot set the attributes directly (to ensure that the validation method is always run):

>>> MyState.foo = 0
Traceback (most recent call last):
...
RuntimeError: Setting attributes directy is not allowed. Use "set" method!

Subclasses will generally override validate to convert from any of the acceptable inputs (such as strings) to the appropriate internal objects:

class MyState(MultiState):

    # define list of allowed attributes
    _attributes = ('foo', 'bar')

    # set default values
    foo = 1
    bar = "guido"

    @classmethod
    def validate(cls, **kwargs):
        assert isinstance(kwargs['foo'], int)
        # etc.
        return kwargs

Notes

This class was adapted from the ScienceState class.

Methods Summary

hook(**kwargs)

A hook which is called everytime when attributes are about to change.

set(*[, _do_validate])

Set the current science state value.

validate(**kwargs)

Validate the keyword arguments and return the (converted) kwargs dictionary.

Methods Documentation

classmethod hook(**kwargs)[source]#

A hook which is called everytime when attributes are about to change.

You should override this method if you want to enable pre-processing or monitoring of your attributes. For example, one could use this to react to attribute changes:

>>> from pycraf.utils import MultiState

>>> class MyState(MultiState):
...
...     _attributes = ('foo', 'bar')
...     foo = 1
...     bar = "guido"
...
...     @classmethod
...     def hook(cls, **kwargs):
...         if 'bar' in kwargs:
...             if kwargs['bar'] != cls.bar:
...                 print('{} about to change: {} --> {}'.format(
...                     'bar', kwargs['bar'], cls.bar
...                     ))
...                 # do stuff ...

>>> _ = MyState.set(bar="david")
bar about to change: david --> guido
>>> _ = MyState.set(bar="david")
>>> _ = MyState.set(bar="guido")
bar about to change: guido --> david

>>> with MyState.set(bar="david"):
...     pass
bar about to change: david --> guido
bar about to change: guido --> david
classmethod set(*, _do_validate=True, **kwargs)[source]#

Set the current science state value.

classmethod validate(**kwargs)[source]#

Validate the keyword arguments and return the (converted) kwargs dictionary.

You should override this method if you want to enable validation of your attributes.

Notes

One doesn’t need to validate the following things, as it is already take care of by the MultiState class:

  • Check that each argument is assigned with a default.

  • Check that the kwargs keys are in _attributes tuple.