Easier and more self documenting patterns for loading/saving Persistent
[python_utils.git] / deferred_operand.py
1 #!/usr/bin/env python3
2
3 # © Copyright 2021-2022, Scott Gasch
4
5 """This is a helper class that tries to define every __dunder__ method
6 so as to defer that evaluation of an object as long as possible.  It
7 is used by smart_future.py as a base class.
8
9 """
10
11 from abc import ABC, abstractmethod
12 from typing import Any, Generic, TypeVar
13
14 # This module is commonly used by others in here and should avoid
15 # taking any unnecessary dependencies back on them.
16
17 T = TypeVar('T')
18
19
20 class DeferredOperand(ABC, Generic[T]):
21     """A wrapper around an operand whose value is deferred until it is
22     needed (i.e. accessed).  See the subclass :class:`SmartFuture` for
23     an example usage and/or a more useful patten.
24     """
25
26     @abstractmethod
27     def _resolve(self, timeout=None) -> T:
28         pass
29
30     @staticmethod
31     def resolve(x: Any) -> Any:
32         while isinstance(x, DeferredOperand):
33             x = x._resolve()
34         return x
35
36     def __lt__(self, other: Any) -> bool:
37         return DeferredOperand.resolve(self) < DeferredOperand.resolve(other)
38
39     def __le__(self, other: Any) -> bool:
40         return DeferredOperand.resolve(self) <= DeferredOperand.resolve(other)
41
42     def __eq__(self, other: Any) -> bool:
43         return DeferredOperand.resolve(self) == DeferredOperand.resolve(other)
44
45     def __ne__(self, other: Any) -> bool:
46         return DeferredOperand.resolve(self) != DeferredOperand.resolve(other)
47
48     def __gt__(self, other: Any) -> bool:
49         return DeferredOperand.resolve(self) > DeferredOperand.resolve(other)
50
51     def __ge__(self, other: Any) -> bool:
52         return DeferredOperand.resolve(self) >= DeferredOperand.resolve(other)
53
54     def __not__(self) -> bool:
55         return not DeferredOperand.resolve(self)
56
57     def bool(self) -> bool:
58         return DeferredOperand.resolve(self)
59
60     def __add__(self, other: Any) -> T:
61         return DeferredOperand.resolve(self) + DeferredOperand.resolve(other)
62
63     def __iadd__(self, other: Any) -> T:
64         return DeferredOperand.resolve(self) + DeferredOperand.resolve(other)
65
66     def __radd__(self, other: Any) -> T:
67         return DeferredOperand.resolve(self) + DeferredOperand.resolve(other)
68
69     def __sub__(self, other: Any) -> T:
70         return DeferredOperand.resolve(self) - DeferredOperand.resolve(other)
71
72     def __mul__(self, other: Any) -> T:
73         return DeferredOperand.resolve(self) * DeferredOperand.resolve(other)
74
75     def __pow__(self, other: Any) -> T:
76         return DeferredOperand.resolve(self) ** DeferredOperand.resolve(other)
77
78     def __truediv__(self, other: Any) -> Any:
79         return DeferredOperand.resolve(self) / DeferredOperand.resolve(other)
80
81     def __floordiv__(self, other: Any) -> T:
82         return DeferredOperand.resolve(self) // DeferredOperand.resolve(other)
83
84     def __contains__(self, other):
85         return DeferredOperand.resolve(other) in DeferredOperand.resolve(self)
86
87     def and_(self, other):
88         return DeferredOperand.resolve(self) & DeferredOperand.resolve(other)
89
90     def or_(self, other):
91         return DeferredOperand.resolve(self) & DeferredOperand.resolve(other)
92
93     def xor(self, other):
94         return DeferredOperand.resolve(self) & DeferredOperand.resolve(other)
95
96     def invert(self):
97         return ~(DeferredOperand.resolve(self))
98
99     def is_(self, other):
100         return DeferredOperand.resolve(self) is DeferredOperand.resolve(other)
101
102     def is_not(self, other):
103         return DeferredOperand.resolve(self) is not DeferredOperand.resolve(other)
104
105     def __abs__(self):
106         return abs(DeferredOperand.resolve(self))
107
108     def setitem(self, k, v):
109         DeferredOperand.resolve(self)[DeferredOperand.resolve(k)] = v
110
111     def delitem(self, k):
112         del DeferredOperand.resolve(self)[DeferredOperand.resolve(k)]
113
114     def getitem(self, k):
115         return DeferredOperand.resolve(self)[DeferredOperand.resolve(k)]
116
117     def lshift(self, other):
118         return DeferredOperand.resolve(self) << DeferredOperand.resolve(other)
119
120     def rshift(self, other):
121         return DeferredOperand.resolve(self) >> DeferredOperand.resolve(other)
122
123     def mod(self, other):
124         return DeferredOperand.resolve(self) % DeferredOperand.resolve(other)
125
126     def matmul(self, other):
127         return DeferredOperand.resolve(self) @ DeferredOperand.resolve(other)
128
129     def neg(self):
130         return -(DeferredOperand.resolve(self))
131
132     def pos(self):
133         return +(DeferredOperand.resolve(self))
134
135     def truth(self):
136         return DeferredOperand.resolve(self)
137
138     def __hash__(self):
139         return DeferredOperand.resolve(self).__hash__()
140
141     def __call__(self):
142         return DeferredOperand.resolve(self)()
143
144     def __iter__(self):
145         return DeferredOperand.resolve(self).__iter__()
146
147     def __repr__(self) -> str:
148         return DeferredOperand.resolve(self).__repr__()
149
150     def __bytes__(self) -> bytes:
151         return DeferredOperand.resolve(self).__bytes__()
152
153     def __int__(self) -> int:
154         return int(DeferredOperand.resolve(self))
155
156     def __float__(self) -> float:
157         return float(DeferredOperand.resolve(self))
158
159     def __getattr__(self, method_name):
160         def method(*args, **kwargs):
161             return getattr(DeferredOperand.resolve(self), method_name)(*args, **kwargs)
162
163         return method