fluent-checks 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,264 @@
1
+ from abc import ABC, abstractmethod
2
+ from itertools import repeat
3
+ from threading import Event, Thread
4
+ import time
5
+ from typing import Callable, Optional, Self, final, override
6
+
7
+ type Condition = Callable[[], bool]
8
+
9
+
10
+ class Check(ABC):
11
+ def __init__(self, condition: Condition) -> None:
12
+ super().__init__()
13
+ self._condition: Condition = condition
14
+
15
+ @final
16
+ def as_bool(self) -> bool:
17
+ return bool(self)
18
+
19
+ def with_delay(self, delay: float) -> "DelayedCheck":
20
+ return DelayedCheck(self, delay)
21
+
22
+ def succeeds_within(self, times: int) -> "RepeatingOrCheck":
23
+ return RepeatingOrCheck(self, times)
24
+
25
+ def is_consistent_for(self, times: int) -> "RepeatingAndCheck":
26
+ return RepeatingAndCheck(self, times)
27
+
28
+ def sometimes(self) -> "LoopingOrCheck":
29
+ return LoopingOrCheck(self)
30
+
31
+ def always(self) -> "LoopingAndCheck":
32
+ return LoopingAndCheck(self)
33
+
34
+ def as_waiting(self) -> "WaitingCheck":
35
+ return WaitingCheck(self)
36
+
37
+ def wait_for(self):
38
+ return self.as_waiting().wait()
39
+
40
+ def with_deadline(self, deadline: float) -> "DeadlineCheck":
41
+ return DeadlineCheck(self, deadline)
42
+
43
+ def with_timeout(self, timeout: float) -> "TimeoutCheck":
44
+ return TimeoutCheck(self, timeout)
45
+
46
+ def raises(self, exception: type[Exception]) -> "RaisesCheck":
47
+ return RaisesCheck(self, exception)
48
+
49
+ def __and__(self, other: Self) -> "Check":
50
+ return AndCheck(self, other)
51
+
52
+ def __or__(self, other: Self) -> "Check":
53
+ return OrCheck(self, other)
54
+
55
+ def __invert__(self) -> "Check":
56
+ return InvertedCheck(self)
57
+
58
+ def __bool__(self) -> bool:
59
+ return self._condition()
60
+
61
+ def __repr__(self) -> str:
62
+ try:
63
+ result = self.as_bool()
64
+ except Exception:
65
+ result = "<error>"
66
+ return f"Check({result})"
67
+
68
+
69
+ class AllCheck(Check):
70
+ def __init__(self, *checks: Check) -> None:
71
+ super().__init__(condition=lambda: all(checks))
72
+ self._checks: tuple[Check, ...] = checks
73
+
74
+ def __repr__(self) -> str:
75
+ return " and ".join([check.__repr__() for check in self._checks])
76
+
77
+
78
+ class AnyCheck(Check):
79
+ def __init__(self, *checks: Check) -> None:
80
+ super().__init__(condition=lambda: any(checks))
81
+ self._checks: tuple[Check, ...] = checks
82
+
83
+ def __repr__(self) -> str:
84
+ return " or ".join([check.__repr__() for check in self._checks])
85
+
86
+
87
+ class AndCheck(AllCheck):
88
+ def __init__(self, left: Check, right: Check) -> None:
89
+ super().__init__(*[left, right])
90
+ self._left: Check = left
91
+ self._right: Check = right
92
+
93
+ def __repr__(self) -> str:
94
+ return f"{self._left.__repr__()} and {self._right.__repr__()}"
95
+
96
+
97
+ class OrCheck(AnyCheck):
98
+ def __init__(self, left: Check, right: Check) -> None:
99
+ super().__init__(*[left, right])
100
+ self._left: Check = left
101
+ self._right: Check = right
102
+
103
+ def __repr__(self) -> str:
104
+ return f"{self._left.__repr__()} or {self._right.__repr__()}"
105
+
106
+
107
+ class InvertedCheck(Check):
108
+ def __init__(self, check: Check) -> None:
109
+ super().__init__(condition=lambda: not check)
110
+ self._inverted: Check = check
111
+
112
+ def __repr__(self) -> str:
113
+ return f"not {self._inverted.__repr__()}"
114
+
115
+
116
+ class DelayedCheck(Check):
117
+ def __init__(self, check: Check, delay: float) -> None:
118
+ super().__init__(condition=lambda: bool(check))
119
+ self._check: Check = check
120
+ self._delay: float = delay
121
+
122
+ @override
123
+ def __bool__(self) -> bool:
124
+ time.sleep(self._delay)
125
+ return self._condition()
126
+
127
+ def __repr__(self) -> str:
128
+ return f"DelayedCheck({self._check.__repr__()}, {self._delay})"
129
+
130
+
131
+ class RepeatingAndCheck(AllCheck):
132
+ def __init__(self, check: Check, times: int) -> None:
133
+ super().__init__(*repeat[Check](check, times))
134
+ self._check: Check = check
135
+ self._times: int = times
136
+
137
+ def __repr__(self) -> str:
138
+ return f"RepeatingAndCheck({self._check.__repr__()}, {self._times})"
139
+
140
+
141
+ class RepeatingOrCheck(AnyCheck):
142
+ def __init__(self, check: Check, times: int) -> None:
143
+ super().__init__(*repeat[Check](check, times))
144
+ self._check: Check = check
145
+ self._times: int = times
146
+
147
+ def __repr__(self) -> str:
148
+ return f"RepeatingOrCheck({self._check.__repr__()}, {self._times})"
149
+
150
+
151
+ class LoopingCheck(Check):
152
+ def __init__(self, check: Check, initial_result: bool) -> None:
153
+ super().__init__(lambda: bool(check))
154
+ self._check: Check = check
155
+ self._result = initial_result
156
+ self._stop_event = Event()
157
+ self._thread: Optional[Thread] = None
158
+
159
+ @abstractmethod
160
+ def _loop(self) -> None:
161
+ pass
162
+
163
+ def __enter__(self) -> Self:
164
+ if self._thread is None:
165
+ self._thread = Thread(target=self._loop)
166
+ self._thread.start()
167
+ return self
168
+
169
+ def __exit__(self, type, value, traceback) -> None:
170
+ if self._thread is not None and self._thread.is_alive():
171
+ self._stop_event.set()
172
+ self._thread.join()
173
+ self._thread = None
174
+
175
+ @override
176
+ def __bool__(self) -> bool:
177
+ return self._result
178
+
179
+ def __repr__(self) -> str:
180
+ return f"LoopingCheck({self._check.__repr__()})"
181
+
182
+
183
+ class LoopingAndCheck(LoopingCheck):
184
+ def __init__(self, check: Check) -> None:
185
+ super().__init__(check, initial_result=True)
186
+
187
+ @override
188
+ def _loop(self) -> None:
189
+ while not self._stop_event.is_set():
190
+ if not self._check.as_bool():
191
+ self._result = False
192
+ time.sleep(0.01)
193
+
194
+ def __repr__(self) -> str:
195
+ return f"LoopingAndCheck({self._check.__repr__()})"
196
+
197
+
198
+ class LoopingOrCheck(LoopingCheck):
199
+ def __init__(self, check: Check) -> None:
200
+ super().__init__(check, initial_result=False)
201
+
202
+ @override
203
+ def _loop(self) -> None:
204
+ while not self._stop_event.is_set():
205
+ if self._check.as_bool():
206
+ self._result = True
207
+ time.sleep(0.01)
208
+
209
+ def __repr__(self) -> str:
210
+ return f"LoopingOrCheck({self._check.__repr__()})"
211
+
212
+
213
+ class WaitingCheck(Check):
214
+ def __init__(self, check: Check) -> None:
215
+ super().__init__(lambda: bool(check))
216
+ self._check: Check = check
217
+
218
+ @override
219
+ def __bool__(self) -> bool:
220
+ while not self._check:
221
+ continue
222
+ return True
223
+
224
+ def wait(self) -> None:
225
+ bool(self)
226
+
227
+ def __repr__(self) -> str:
228
+ return f"WatingCheck({self._check.__repr__()})"
229
+
230
+
231
+ class DeadlineCheck(Check):
232
+ def __init__(self, check: Check, deadline: float) -> None:
233
+ super().__init__(lambda: bool(check) if time.time() < deadline else False)
234
+ self._check: Check = check
235
+ self._deadline: float = deadline
236
+
237
+ def __repr__(self) -> str:
238
+ return f"DeadlineCheck({self._check.__repr__()}, {self._deadline})"
239
+
240
+
241
+ class TimeoutCheck(DeadlineCheck):
242
+ def __init__(self, check: Check, timeout: float) -> None:
243
+ super().__init__(check, time.time() + timeout)
244
+ self._timeout: float = timeout
245
+
246
+ def __repr__(self) -> str:
247
+ return f"TimeoutCheck({self._check.__repr__()}, {self._timeout})"
248
+
249
+
250
+ class RaisesCheck(Check):
251
+ def __init__(self, check: Check, exception: type[Exception]) -> None:
252
+ super().__init__(condition=lambda: bool(check))
253
+ self._check: Check = check
254
+ self._exception: type[Exception] = exception
255
+
256
+ def __bool__(self) -> bool:
257
+ try:
258
+ self._condition()
259
+ return False
260
+ except self._exception:
261
+ return True
262
+
263
+ def __repr__(self) -> str:
264
+ return f"RaisesCheck({self._check.__repr__()}, {self._exception.__name__})"
fluent_checks/py.typed ADDED
File without changes
@@ -0,0 +1,21 @@
1
+ Metadata-Version: 2.3
2
+ Name: fluent-checks
3
+ Version: 0.1.0
4
+ Summary: A library for creating fluent, readable, and composable checks for your tests or application logic.
5
+ Keywords: fluent,checks,testing,assertions,validation
6
+ Author: vantorrewannes
7
+ Author-email: vantorrewannes <vantorrewannes@gmail.com>
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Topic :: Software Development :: Testing
14
+ Classifier: Topic :: Utilities
15
+ Requires-Python: >=3.12
16
+ Project-URL: Bug Tracker, https://github.com/VantorreWannes/fluent-checks/issues
17
+ Project-URL: Homepage, https://github.com/VantorreWannes/fluent-checks
18
+ Description-Content-Type: text/markdown
19
+
20
+ # fluent-checks
21
+ A simple, lightweight library for creating fluent, readable, and chainable checks in Python.
@@ -0,0 +1,5 @@
1
+ fluent_checks/__init__.py,sha256=PASUV-AhQlKCxoINTREjcmJhhViBUqim3OM6HOMqoTg,7720
2
+ fluent_checks/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ fluent_checks-0.1.0.dist-info/WHEEL,sha256=4n27za1eEkOnA7dNjN6C5-O2rUiw6iapszm14Uj-Qmk,79
4
+ fluent_checks-0.1.0.dist-info/METADATA,sha256=_8MUtV5lmMr7iSVzhKe-CEei31zUW6pLw22LGIOiUH8,943
5
+ fluent_checks-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: uv 0.8.13
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any