Completed
Push — develop ( b9d7ca...e13534 )
by Jace
01:46
created

yorm.bases.fetch_before()   A

Complexity

Conditions 4

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 4
Metric Value
cc 4
dl 0
loc 14
ccs 11
cts 11
cp 1
crap 4
rs 9.2
1
"""Base classes for mapping."""
2
3 1
import abc
4 1
import functools
5
6 1
from .. import common
7 1
from ..mapper import MAPPER, get_mapper
8
9
10 1
log = common.logger(__name__)
11
12
13 1
def fetch_before(method):
14
    """Decorator for methods that should fetch before call."""
15 1
    @functools.wraps(method)
16
    def fetch_before(self, *args, **kwargs):  # pylint: disable=W0621
17
        """Decorated method."""
18 1
        mapper = get_mapper(self)
19 1
        if mapper and mapper.modified:
20 1
            log.debug("fetch before call: %s", method.__name__)
21 1
            mapper.fetch()
22 1
            if mapper.auto_store:
23 1
                mapper.store()
24 1
                mapper.modified = False
25 1
        return method(self, *args, **kwargs)
26 1
    return fetch_before
27
28
29 1
def store_after(method):
30
    """Decorator for methods that should store after call."""
31 1
    @functools.wraps(method)
32
    def store_after(self, *args, **kwargs):  # pylint: disable=W0621
33
        """Decorated method."""
34 1
        result = method(self, *args, **kwargs)
35 1
        mapper = get_mapper(self)
36 1
        if mapper and mapper.auto:
37 1
            log.debug("store after call: %s", method.__name__)
38 1
            mapper.store()
39 1
        return result
40 1
    return store_after
41
42
43 1
class Mappable(metaclass=abc.ABCMeta):  # pylint: disable=R0201
44
    """Base class for objects with attributes mapped to file."""
45
46
    # pylint: disable=no-member
47
48 1
    def __getattribute__(self, name):
49
        """Trigger object update when reading attributes."""
50
        # TODO: remove MAPPER once renamed to '__mapper__'
51 1
        if name.startswith('__') or name == MAPPER:
52
            # avoid infinite recursion (attribute requested in this function)
53 1
            return object.__getattribute__(self, name)
54
55 1
        mapper = get_mapper(self)
56
57
        # Get the attribute's current value
58 1
        try:
59 1
            value = object.__getattribute__(self, name)
60 1
        except AttributeError as exc:
61 1
            missing = True
62 1
            if not mapper:
63 1
                raise exc from None
64
        else:
65 1
            missing = False
66
67
        # Fetch a new value from disk if the attribute is mapped or missing
68 1
        if mapper and (missing or (name in mapper.attrs and mapper.modified)):
69 1
            mapper.fetch()
70 1
            value = object.__getattribute__(self, name)
71
72
            # Store back to disk if this has been done before
73 1
            if mapper.auto_store:
74 1
                mapper.store()
75 1
                mapper.modified = False
76
77 1
        return value
78
79 1
    def __setattr__(self, name, value):
80
        """Trigger file update when setting attributes."""
81 1
        super().__setattr__(name, value)
82 1
        if name.startswith('__'):
83 1
            return
84
85 1
        mapper = get_mapper(self)
86 1
        if mapper and mapper.auto and name in mapper.attrs:
87 1
            mapper.store()
88
89 1
    @fetch_before
90
    def __iter__(self):
91
        """Trigger object update when iterating."""
92 1
        return super().__iter__()
93
94 1
    @fetch_before
95
    def __getitem__(self, key):
96
        """Trigger object update when reading an index."""
97 1
        return super().__getitem__(key)
98
99 1
    @store_after
100
    def __setitem__(self, key, value):
101
        """Trigger file update when setting an index."""
102 1
        super().__setitem__(key, value)
103
104 1
    @store_after
105
    def __delitem__(self, key):
106
        """Trigger file update when deleting an index."""
107 1
        super().__delitem__(key)
108
109 1
    @store_after
110
    def append(self, value):
111
        """Trigger file update when appending items."""
112
        super().append(value)
113