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