This repository has been archived by the owner on Oct 12, 2023. It is now read-only.
generated from KOLANICH/python_project_boilerplate.py
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathfields.py
139 lines (97 loc) · 3.64 KB
/
fields.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
import typing
from abc import ABC, abstractmethod
from .core import KeyT
from .mappers import ColdMapper, HotMapper
class FieldStrategy(ABC):
"""Defines a storage-backed field in a class."""
__slots__ = ("name", "cold")
def __init__(self, cold: ColdMapper, name: typing.Optional[str] = None) -> None:
self.name = name
self.cold = cold
@abstractmethod
def get(self, parent: "_ProtoBundle", key: KeyT) -> typing.Any:
raise NotImplementedError
@abstractmethod
def set(self, parent: "_ProtoBundle", key: KeyT, newV: typing.Any) -> None:
raise NotImplementedError
class ColdStrategy(FieldStrategy):
"""Defines a storage-backed uncached immediately-written field in a class."""
__slots__ = ()
def get(self, parent: "_ProtoBundle", key: KeyT) -> typing.Any:
return self.cold.load(parent, self, key)
def set(self, parent: "_ProtoBundle", key: KeyT, newV: typing.Any) -> None:
self.cold.save(parent, self, key, newV)
class CachedStrategy(FieldStrategy):
"""Defines a storage-backed cached field in a class."""
__slots__ = ("hot", "modified")
def __init__(self, cold: ColdMapper, hot: HotMapper, name: typing.Optional[str] = None) -> None:
super().__init__(cold, name)
self.hot = hot
self.modified = set()
def get(self, parent: "_ProtoBundle", key: KeyT) -> typing.Any:
res = self.hot.load(parent, self, key)
if res is None:
res = self.cold.load(parent, self, key)
self.hot.save(parent, self, key, res)
return res
def set(self, parent: "_ProtoBundle", key: KeyT, newV: typing.Any) -> None:
self.hot.save(parent, self, key, newV)
self.modified |= {key}
def _saveItem(self, parent: "_ProtoBundle", key: KeyT) -> None:
res = self.hot.load(parent, self, key)
self.cold.save(parent, self, key, res)
def save(self, parent: "_ProtoBundle", key: KeyT = None) -> None:
if key is not None:
self._saveItem(parent, key)
self.modified -= {key}
else:
self._saveAll(parent)
def _saveAll(self, parent: "_ProtoBundle") -> None:
for key in self.modified:
self._saveItem(parent, key)
self.modified = type(self.modified)()
class _Field:
__slots__ = ("strategy",)
def __init__(self, strategy) -> None:
self.strategy = strategy
def __set_name__(self, owner: typing.Type["_ProtoBundle"], name: str) -> None:
if self.strategy.name is None:
self.strategy.name = name
def save(self, parent: "_ProtoBundle"):
return self.strategy.save(parent)
class Field(_Field):
__slots__ = ()
def __init__(self, cold: ColdMapper, hot: HotMapper = None, name: typing.Optional[str] = None) -> None:
if hot is None:
strategy = ColdStrategy(cold, name)
else:
strategy = CachedStrategy(cold, hot, name)
super().__init__(strategy)
class Field0D(Field):
__slots__ = ()
def __get__(self, inst: "_ProtoBundle", cls: typing.Optional[typing.Type["_ProtoBundle"]] = None) -> typing.Any:
if inst is not None:
return self.strategy.get(inst, ())
else:
return self
def __set__(self, inst: "_ProtoBundle", newV: typing.Any) -> None:
if inst is not None:
self.strategy.set(inst, (), newV)
class FieldNDAccessor:
__slots__ = ("strategy", "parent")
def __init__(self, strategy, parent):
self.strategy = strategy
self.parent = parent
def __getitem__(self, key: KeyT) -> typing.Any:
return self.strategy.get(self.parent, key)
def __setitem__(self, key: KeyT, newV: typing.Any) -> None:
self.strategy.set(self.parent, key, newV)
class FieldND(Field):
__slots__ = ()
def __get__(self, inst: "_ProtoBundle", cls=None) -> typing.Any:
if inst is not None:
return FieldNDAccessor(self.strategy, inst)
else:
return self
def __set__(self, inst: "_ProtoBundle", newV: typing.Any) -> None:
raise NotImplementedError