Passed
Push — master ( cc7a4b...4d42d8 )
by Konstantinos
43s queued 14s
created

so_magic.data.datapoints_manager   A

Complexity

Total Complexity 6

Size/Duplication

Total Lines 69
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 29
dl 0
loc 69
rs 10
c 0
b 0
f 0
wmc 6

3 Methods

Rating   Name   Duplication   Size   Complexity  
A DatapointsManager.state() 0 8 1
A DatapointsManager.datapoints() 0 12 2
A DatapointsManager.update() 0 22 3
1
"""Defines the DatapointsManager type (class); a centralized facility where all
2
datapoints objects should arrived and be retrieved from."""
3
from typing import Iterable, Optional
4
import logging
5
import attr
6
from so_magic.utils import Observer, Subject
7
8
logger = logging.getLogger(__name__)
9
10
11
@attr.s
12
class DatapointsManager(Observer):
13
    """Manage operations revolved around datapoints collection objects.
14
15
    Instances of this class are able to monitor (listener/observer pattern) the creation of
16
    datapoints collection objects and store them in a dictionary structure.
17
    They also provide retrieval methods to the client to "pick up" a datapoints object.
18
19
    Args:
20
        datapoints_objects (dict, optional): the initial structure that stores datapoints objects
21
    """
22
    datapoints_objects = attr.ib(init=True, default={})
23
    _last_key = attr.ib(init=False, default='')
24
25
    def update(self, subject: Subject):
26
        """Update our state based on the event/observation captured/made.
27
28
        Stores the datapoints object observed in a dictionary using a the Subject
29
        name attribute as key.
30
31
        Args:
32
            subject (Subject): the subject object observed; it acts as an event
33
34
        Raises:
35
            RuntimeError: in case there is no 'name' attribute on the subject or if it is an empty string ''
36
            RuntimeError: in case the 'name' attribute on the subject has already been used to store a datapoints object
37
        """
38
        datapoints_object = subject.state
39
        key = getattr(subject, 'name', '')
40
        if key == '':
41
            raise RuntimeError(f'Subject {subject} with state {str(subject.state)} resulted in an empty string as key.'
42
                               f'We reject the key, since it is going to "query" a in dict/hash).')
43
        if key in self.datapoints_objects:
44
            raise RuntimeError(f"Attempted to register a new Datapoints object at the existing key '{key}'.")
45
        self.datapoints_objects[key] = datapoints_object
46
        self._last_key = key
47
48
    @property
49
    def state(self):
50
        """The latest (most recent) key used to store a datapoints object.
51
52
        Returns:
53
            str: the key under which we stored a datapoints object last time
54
        """
55
        return self._last_key
56
57
    @property
58
    def datapoints(self) -> Optional[Iterable]:  # indicates that the method can return an Iterable or None types
59
        """The most recently stored datapoints object.
60
61
        Returns:
62
            Optional[Iterable]: the reference to the datapoints object
63
        """
64
        try:
65
            return self.datapoints_objects[self._last_key]
66
        except KeyError as exception:
67
            logger.error("%s . Requested datapoints with id '%s', but was not found in registered [%s]",
68
                         exception, self._last_key, {', '.join(_ for _ in self.datapoints_objects.keys())})
69