More work to improve documentation generated by sphinx. Also fixes
[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
6 :class:`pyutils.parallelize.smart_future.SmartFuture`, which is a
7 piece of the simple parallelization framework.
8
9 This base class is essentially tries to have every Python `__dunder__`
10 method defined with a reasonabe default implementation so that, when
11 it is used in a manner that requires the value to be known, it calls
12 :meth:`DeferredOperand.resolve` and either gets the requisite value or
13 blocks until the data necessary to resolve the value is ready.  This
14 is meant to enable more transparent :class:`Future` objects that can
15 be just used directly.
16
17 See :class:`pyutils.parallelize.smart_future.SmartFuture` for more
18 information.
19
20 """
21
22 from abc import ABC, abstractmethod
23 from typing import Any, Generic, TypeVar
24
25 # This module is commonly used by others in here and should avoid
26 # taking any unnecessary dependencies back on them.
27
28 T = TypeVar('T')
29
30
31 class DeferredOperand(ABC, Generic[T]):
32     """A wrapper around an operand whose value is deferred until it is
33     needed (i.e. accessed).  See the subclass
34     :class:`pyutils.parallelize.smart_future.SmartFuture` for an
35     example usage and/or a more useful patten.
36
37     """
38
39     @abstractmethod
40     def _resolve(self, timeout=None) -> T:
41         pass
42
43     @staticmethod
44     def resolve(x: Any) -> Any:
45         """
46         When this object is used in a manner that requires it to know
47         its value, this method is called to either return the value or
48         block until it can do so.
49
50         Args:
51             x: the object whose value is required
52
53         Returns:
54             The value of x... immediately if possible, eventually if
55             not possible.
56         """
57         while isinstance(x, DeferredOperand):
58             x = x._resolve()
59         return x
60
61     def __lt__(self, other: Any) -> bool:
62         return DeferredOperand.resolve(self) < DeferredOperand.resolve(other)
63
64     def __le__(self, other: Any) -> bool:
65         return DeferredOperand.resolve(self) <= DeferredOperand.resolve(other)
66
67     def __eq__(self, other: Any) -> bool:
68         return DeferredOperand.resolve(self) == DeferredOperand.resolve(other)
69
70     def __ne__(self, other: Any) -> bool:
71         return DeferredOperand.resolve(self) != DeferredOperand.resolve(other)
72
73     def __gt__(self, other: Any) -> bool:
74         return DeferredOperand.resolve(self) > DeferredOperand.resolve(other)
75
76     def __ge__(self, other: Any) -> bool:
77         return DeferredOperand.resolve(self) >= DeferredOperand.resolve(other)
78
79     def __not__(self) -> bool:
80         return not DeferredOperand.resolve(self)
81
82     def bool(self) -> bool:
83         return DeferredOperand.resolve(self)
84
85     def __add__(self, other: Any) -> T:
86         return DeferredOperand.resolve(self) + DeferredOperand.resolve(other)
87
88     def __iadd__(self, other: Any) -> T:
89         return DeferredOperand.resolve(self) + DeferredOperand.resolve(other)
90
91     def __radd__(self, other: Any) -> T:
92         return DeferredOperand.resolve(self) + DeferredOperand.resolve(other)
93
94     def __sub__(self, other: Any) -> T:
95         return DeferredOperand.resolve(self) - DeferredOperand.resolve(other)
96
97     def __mul__(self, other: Any) -> T:
98         return DeferredOperand.resolve(self) * DeferredOperand.resolve(other)
99
100     def __pow__(self, other: Any) -> T:
101         return DeferredOperand.resolve(self) ** DeferredOperand.resolve(other)
102
103     def __truediv__(self, other: Any) -> Any:
104         return DeferredOperand.resolve(self) / DeferredOperand.resolve(other)
105
106     def __floordiv__(self, other: Any) -> T:
107         return DeferredOperand.resolve(self) // DeferredOperand.resolve(other)
108
109     def __contains__(self, other):
110         return DeferredOperand.resolve(other) in DeferredOperand.resolve(self)
111
112     def and_(self, other):
113         return DeferredOperand.resolve(self) & DeferredOperand.resolve(other)
114
115     def or_(self, other):
116         return DeferredOperand.resolve(self) & DeferredOperand.resolve(other)
117
118     def xor(self, other):
119         return DeferredOperand.resolve(self) & DeferredOperand.resolve(other)
120
121     def invert(self):
122         return ~(DeferredOperand.resolve(self))
123
124     def is_(self, other):
125         return DeferredOperand.resolve(self) is DeferredOperand.resolve(other)
126
127     def is_not(self, other):
128         return DeferredOperand.resolve(self) is not DeferredOperand.resolve(other)
129
130     def __abs__(self):
131         return abs(DeferredOperand.resolve(self))
132
133     def setitem(self, k, v):
134         DeferredOperand.resolve(self)[DeferredOperand.resolve(k)] = v
135
136     def delitem(self, k):
137         del DeferredOperand.resolve(self)[DeferredOperand.resolve(k)]
138
139     def getitem(self, k):
140         return DeferredOperand.resolve(self)[DeferredOperand.resolve(k)]
141
142     def lshift(self, other):
143         return DeferredOperand.resolve(self) << DeferredOperand.resolve(other)
144
145     def rshift(self, other):
146         return DeferredOperand.resolve(self) >> DeferredOperand.resolve(other)
147
148     def mod(self, other):
149         return DeferredOperand.resolve(self) % DeferredOperand.resolve(other)
150
151     def matmul(self, other):
152         return DeferredOperand.resolve(self) @ DeferredOperand.resolve(other)
153
154     def neg(self):
155         return -(DeferredOperand.resolve(self))
156
157     def pos(self):
158         return +(DeferredOperand.resolve(self))
159
160     def truth(self):
161         return DeferredOperand.resolve(self)
162
163     def __hash__(self):
164         return DeferredOperand.resolve(self).__hash__()
165
166     def __call__(self):
167         return DeferredOperand.resolve(self)()
168
169     def __iter__(self):
170         return DeferredOperand.resolve(self).__iter__()
171
172     def __repr__(self) -> str:
173         return DeferredOperand.resolve(self).__repr__()
174
175     def __bytes__(self) -> bytes:
176         return DeferredOperand.resolve(self).__bytes__()
177
178     def __int__(self) -> int:
179         return int(DeferredOperand.resolve(self))
180
181     def __float__(self) -> float:
182         return float(DeferredOperand.resolve(self))
183
184     def __getattr__(self, method_name):
185         def method(*args, **kwargs):
186             return getattr(DeferredOperand.resolve(self), method_name)(*args, **kwargs)
187
188         return method