assertpy2 2.0.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.
- assertpy2/__init__.py +25 -0
- assertpy2/assertpy.py +468 -0
- assertpy2/base.py +435 -0
- assertpy2/collection.py +217 -0
- assertpy2/contains.py +386 -0
- assertpy2/date.py +219 -0
- assertpy2/dict.py +255 -0
- assertpy2/dynamic.py +113 -0
- assertpy2/exception.py +128 -0
- assertpy2/extracting.py +233 -0
- assertpy2/file.py +276 -0
- assertpy2/helpers.py +273 -0
- assertpy2/numeric.py +555 -0
- assertpy2/py.typed +0 -0
- assertpy2/snapshot.py +217 -0
- assertpy2/string.py +413 -0
- assertpy2-2.0.0.dist-info/METADATA +227 -0
- assertpy2-2.0.0.dist-info/RECORD +20 -0
- assertpy2-2.0.0.dist-info/WHEEL +4 -0
- assertpy2-2.0.0.dist-info/licenses/LICENSE +28 -0
assertpy2/numeric.py
ADDED
|
@@ -0,0 +1,555 @@
|
|
|
1
|
+
# Copyright (c) 2015-2019, Activision Publishing, Inc.
|
|
2
|
+
# All rights reserved.
|
|
3
|
+
#
|
|
4
|
+
# Redistribution and use in source and binary forms, with or without modification,
|
|
5
|
+
# are permitted provided that the following conditions are met:
|
|
6
|
+
#
|
|
7
|
+
# 1. Redistributions of source code must retain the above copyright notice, this
|
|
8
|
+
# list of conditions and the following disclaimer.
|
|
9
|
+
#
|
|
10
|
+
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
11
|
+
# this list of conditions and the following disclaimer in the documentation
|
|
12
|
+
# and/or other materials provided with the distribution.
|
|
13
|
+
#
|
|
14
|
+
# 3. Neither the name of the copyright holder nor the names of its contributors
|
|
15
|
+
# may be used to endorse or promote products derived from this software without
|
|
16
|
+
# specific prior written permission.
|
|
17
|
+
#
|
|
18
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
19
|
+
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
20
|
+
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
21
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
|
22
|
+
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
23
|
+
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
24
|
+
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
25
|
+
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
26
|
+
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
27
|
+
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
28
|
+
|
|
29
|
+
from __future__ import annotations
|
|
30
|
+
|
|
31
|
+
import datetime
|
|
32
|
+
import math
|
|
33
|
+
import numbers
|
|
34
|
+
from typing import TYPE_CHECKING
|
|
35
|
+
|
|
36
|
+
if TYPE_CHECKING:
|
|
37
|
+
from typing_extensions import Self
|
|
38
|
+
|
|
39
|
+
__tracebackhide__ = True
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class NumericMixin:
|
|
43
|
+
"""Numeric assertions mixin."""
|
|
44
|
+
|
|
45
|
+
_NUMERIC_COMPAREABLE = frozenset({datetime.datetime, datetime.timedelta, datetime.date, datetime.time})
|
|
46
|
+
_NUMERIC_NON_COMPAREABLE = frozenset({complex})
|
|
47
|
+
|
|
48
|
+
def _validate_compareable(self, other):
|
|
49
|
+
self_type = type(self.val)
|
|
50
|
+
other_type = type(other)
|
|
51
|
+
|
|
52
|
+
if self_type in self._NUMERIC_NON_COMPAREABLE:
|
|
53
|
+
raise TypeError("ordering is not defined for type <%s>" % self_type.__name__)
|
|
54
|
+
if self_type in self._NUMERIC_COMPAREABLE:
|
|
55
|
+
if other_type is not self_type:
|
|
56
|
+
raise TypeError("given arg must be <%s>, but was <%s>" % (self_type.__name__, other_type.__name__))
|
|
57
|
+
return
|
|
58
|
+
if isinstance(self.val, numbers.Number):
|
|
59
|
+
if not isinstance(other, numbers.Number):
|
|
60
|
+
raise TypeError("given arg must be a number, but was <%s>" % other_type.__name__)
|
|
61
|
+
return
|
|
62
|
+
try:
|
|
63
|
+
_ = self.val < other
|
|
64
|
+
except TypeError:
|
|
65
|
+
raise TypeError("ordering is not defined for type <%s>" % self_type.__name__) from None
|
|
66
|
+
|
|
67
|
+
def _validate_number(self):
|
|
68
|
+
"""Raise TypeError if val is not numeric."""
|
|
69
|
+
if isinstance(self.val, numbers.Number) is False:
|
|
70
|
+
raise TypeError("val is not numeric")
|
|
71
|
+
|
|
72
|
+
def _validate_real(self):
|
|
73
|
+
"""Raise TypeError if val is not real number."""
|
|
74
|
+
if isinstance(self.val, numbers.Real) is False:
|
|
75
|
+
raise TypeError("val is not real number")
|
|
76
|
+
|
|
77
|
+
def is_zero(self) -> Self:
|
|
78
|
+
"""Asserts that val is numeric and is zero.
|
|
79
|
+
|
|
80
|
+
Examples:
|
|
81
|
+
Usage::
|
|
82
|
+
|
|
83
|
+
assert_that(0).is_zero()
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
AssertionBuilder: returns this instance to chain to the next assertion
|
|
87
|
+
|
|
88
|
+
Raises:
|
|
89
|
+
AssertionError: if val is **not** zero
|
|
90
|
+
"""
|
|
91
|
+
self._validate_number()
|
|
92
|
+
return self.is_equal_to(0)
|
|
93
|
+
|
|
94
|
+
def is_not_zero(self) -> Self:
|
|
95
|
+
"""Asserts that val is numeric and is *not* zero.
|
|
96
|
+
|
|
97
|
+
Examples:
|
|
98
|
+
Usage::
|
|
99
|
+
|
|
100
|
+
assert_that(1).is_not_zero()
|
|
101
|
+
assert_that(123.4).is_not_zero()
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
AssertionBuilder: returns this instance to chain to the next assertion
|
|
105
|
+
|
|
106
|
+
Raises:
|
|
107
|
+
AssertionError: if val **is** zero
|
|
108
|
+
"""
|
|
109
|
+
self._validate_number()
|
|
110
|
+
return self.is_not_equal_to(0)
|
|
111
|
+
|
|
112
|
+
def is_nan(self) -> Self:
|
|
113
|
+
"""Asserts that val is real number and is ``NaN`` (not a number).
|
|
114
|
+
|
|
115
|
+
Examples:
|
|
116
|
+
Usage::
|
|
117
|
+
|
|
118
|
+
assert_that(float('nan')).is_nan()
|
|
119
|
+
assert_that(float('inf') * 0).is_nan()
|
|
120
|
+
|
|
121
|
+
Returns:
|
|
122
|
+
AssertionBuilder: returns this instance to chain to the next assertion
|
|
123
|
+
|
|
124
|
+
Raises:
|
|
125
|
+
AssertionError: if val is **not** NaN
|
|
126
|
+
"""
|
|
127
|
+
self._validate_number()
|
|
128
|
+
self._validate_real()
|
|
129
|
+
if not math.isnan(self.val):
|
|
130
|
+
return self.error("Expected <%s> to be <NaN>, but was not." % self.val)
|
|
131
|
+
return self
|
|
132
|
+
|
|
133
|
+
def is_not_nan(self) -> Self:
|
|
134
|
+
"""Asserts that val is real number and is *not* ``NaN`` (not a number).
|
|
135
|
+
|
|
136
|
+
Examples:
|
|
137
|
+
Usage::
|
|
138
|
+
|
|
139
|
+
assert_that(0).is_not_nan()
|
|
140
|
+
assert_that(123.4).is_not_nan()
|
|
141
|
+
assert_that(float('inf')).is_not_nan()
|
|
142
|
+
|
|
143
|
+
Returns:
|
|
144
|
+
AssertionBuilder: returns this instance to chain to the next assertion
|
|
145
|
+
|
|
146
|
+
Raises:
|
|
147
|
+
AssertionError: if val **is** NaN
|
|
148
|
+
"""
|
|
149
|
+
self._validate_number()
|
|
150
|
+
self._validate_real()
|
|
151
|
+
if math.isnan(self.val):
|
|
152
|
+
return self.error("Expected not <NaN>, but was.")
|
|
153
|
+
return self
|
|
154
|
+
|
|
155
|
+
def is_inf(self) -> Self:
|
|
156
|
+
"""Asserts that val is real number and is ``Inf`` (infinity).
|
|
157
|
+
|
|
158
|
+
Examples:
|
|
159
|
+
Usage::
|
|
160
|
+
|
|
161
|
+
assert_that(float('inf')).is_inf()
|
|
162
|
+
assert_that(float('inf') * 1).is_inf()
|
|
163
|
+
|
|
164
|
+
Returns:
|
|
165
|
+
AssertionBuilder: returns this instance to chain to the next assertion
|
|
166
|
+
|
|
167
|
+
Raises:
|
|
168
|
+
AssertionError: if val is **not** Inf
|
|
169
|
+
"""
|
|
170
|
+
self._validate_number()
|
|
171
|
+
self._validate_real()
|
|
172
|
+
if not math.isinf(self.val):
|
|
173
|
+
return self.error("Expected <%s> to be <Inf>, but was not." % self.val)
|
|
174
|
+
return self
|
|
175
|
+
|
|
176
|
+
def is_not_inf(self) -> Self:
|
|
177
|
+
"""Asserts that val is real number and is *not* ``Inf`` (infinity).
|
|
178
|
+
|
|
179
|
+
Examples:
|
|
180
|
+
Usage::
|
|
181
|
+
|
|
182
|
+
assert_that(0).is_not_inf()
|
|
183
|
+
assert_that(123.4).is_not_inf()
|
|
184
|
+
assert_that(float('nan')).is_not_inf()
|
|
185
|
+
|
|
186
|
+
Returns:
|
|
187
|
+
AssertionBuilder: returns this instance to chain to the next assertion
|
|
188
|
+
|
|
189
|
+
Raises:
|
|
190
|
+
AssertionError: if val **is** Inf
|
|
191
|
+
"""
|
|
192
|
+
self._validate_number()
|
|
193
|
+
self._validate_real()
|
|
194
|
+
if math.isinf(self.val):
|
|
195
|
+
return self.error("Expected not <Inf>, but was.")
|
|
196
|
+
return self
|
|
197
|
+
|
|
198
|
+
def is_greater_than(self, other) -> Self:
|
|
199
|
+
"""Asserts that val is numeric and is greater than other.
|
|
200
|
+
|
|
201
|
+
Args:
|
|
202
|
+
other: the other date, expected to be less than val
|
|
203
|
+
|
|
204
|
+
Examples:
|
|
205
|
+
Usage::
|
|
206
|
+
|
|
207
|
+
assert_that(1).is_greater_than(0)
|
|
208
|
+
assert_that(123.4).is_greater_than(111.1)
|
|
209
|
+
|
|
210
|
+
For dates, behavior is identical to :meth:`~assertpy.date.DateMixin.is_after`::
|
|
211
|
+
|
|
212
|
+
import datetime
|
|
213
|
+
|
|
214
|
+
today = datetime.datetime.now()
|
|
215
|
+
yesterday = today - datetime.timedelta(days=1)
|
|
216
|
+
|
|
217
|
+
assert_that(today).is_greater_than(yesterday)
|
|
218
|
+
|
|
219
|
+
Returns:
|
|
220
|
+
AssertionBuilder: returns this instance to chain to the next assertion
|
|
221
|
+
|
|
222
|
+
Raises:
|
|
223
|
+
AssertionError: if val is **not** greater than other
|
|
224
|
+
"""
|
|
225
|
+
self._validate_compareable(other)
|
|
226
|
+
if self.val <= other:
|
|
227
|
+
if type(self.val) is datetime.datetime:
|
|
228
|
+
return self.error(
|
|
229
|
+
"Expected <%s> to be greater than <%s>, but was not."
|
|
230
|
+
% (self.val.strftime("%Y-%m-%d %H:%M:%S"), other.strftime("%Y-%m-%d %H:%M:%S"))
|
|
231
|
+
)
|
|
232
|
+
else:
|
|
233
|
+
return self.error("Expected <%s> to be greater than <%s>, but was not." % (self.val, other))
|
|
234
|
+
return self
|
|
235
|
+
|
|
236
|
+
def is_greater_than_or_equal_to(self, other) -> Self:
|
|
237
|
+
"""Asserts that val is numeric and is greater than or equal to other.
|
|
238
|
+
|
|
239
|
+
Args:
|
|
240
|
+
other: the other date, expected to be less than or equal to val
|
|
241
|
+
|
|
242
|
+
Examples:
|
|
243
|
+
Usage::
|
|
244
|
+
|
|
245
|
+
assert_that(1).is_greater_than_or_equal_to(0)
|
|
246
|
+
assert_that(1).is_greater_than_or_equal_to(1)
|
|
247
|
+
assert_that(123.4).is_greater_than_or_equal_to(111.1)
|
|
248
|
+
|
|
249
|
+
For dates, behavior is identical to :meth:`~assertpy.date.DateMixin.is_after` *except* when equal::
|
|
250
|
+
|
|
251
|
+
import datetime
|
|
252
|
+
|
|
253
|
+
today = datetime.datetime.now()
|
|
254
|
+
yesterday = today - datetime.timedelta(days=1)
|
|
255
|
+
|
|
256
|
+
assert_that(today).is_greater_than_or_equal_to(yesterday)
|
|
257
|
+
assert_that(today).is_greater_than_or_equal_to(today)
|
|
258
|
+
|
|
259
|
+
Returns:
|
|
260
|
+
AssertionBuilder: returns this instance to chain to the next assertion
|
|
261
|
+
|
|
262
|
+
Raises:
|
|
263
|
+
AssertionError: if val is **not** greater than or equal to other
|
|
264
|
+
"""
|
|
265
|
+
self._validate_compareable(other)
|
|
266
|
+
if self.val < other:
|
|
267
|
+
if type(self.val) is datetime.datetime:
|
|
268
|
+
return self.error(
|
|
269
|
+
"Expected <%s> to be greater than or equal to <%s>, but was not."
|
|
270
|
+
% (self.val.strftime("%Y-%m-%d %H:%M:%S"), other.strftime("%Y-%m-%d %H:%M:%S"))
|
|
271
|
+
)
|
|
272
|
+
else:
|
|
273
|
+
return self.error("Expected <%s> to be greater than or equal to <%s>, but was not." % (self.val, other))
|
|
274
|
+
return self
|
|
275
|
+
|
|
276
|
+
def is_less_than(self, other) -> Self:
|
|
277
|
+
"""Asserts that val is numeric and is less than other.
|
|
278
|
+
|
|
279
|
+
Args:
|
|
280
|
+
other: the other date, expected to be greater than val
|
|
281
|
+
|
|
282
|
+
Examples:
|
|
283
|
+
Usage::
|
|
284
|
+
|
|
285
|
+
assert_that(0).is_less_than(1)
|
|
286
|
+
assert_that(123.4).is_less_than(555.5)
|
|
287
|
+
|
|
288
|
+
For dates, behavior is identical to :meth:`~assertpy.date.DateMixin.is_before`::
|
|
289
|
+
|
|
290
|
+
import datetime
|
|
291
|
+
|
|
292
|
+
today = datetime.datetime.now()
|
|
293
|
+
yesterday = today - datetime.timedelta(days=1)
|
|
294
|
+
|
|
295
|
+
assert_that(yesterday).is_less_than(today)
|
|
296
|
+
|
|
297
|
+
Returns:
|
|
298
|
+
AssertionBuilder: returns this instance to chain to the next assertion
|
|
299
|
+
|
|
300
|
+
Raises:
|
|
301
|
+
AssertionError: if val is **not** less than other
|
|
302
|
+
"""
|
|
303
|
+
self._validate_compareable(other)
|
|
304
|
+
if self.val >= other:
|
|
305
|
+
if type(self.val) is datetime.datetime:
|
|
306
|
+
return self.error(
|
|
307
|
+
"Expected <%s> to be less than <%s>, but was not."
|
|
308
|
+
% (self.val.strftime("%Y-%m-%d %H:%M:%S"), other.strftime("%Y-%m-%d %H:%M:%S"))
|
|
309
|
+
)
|
|
310
|
+
else:
|
|
311
|
+
return self.error("Expected <%s> to be less than <%s>, but was not." % (self.val, other))
|
|
312
|
+
return self
|
|
313
|
+
|
|
314
|
+
def is_less_than_or_equal_to(self, other) -> Self:
|
|
315
|
+
"""Asserts that val is numeric and is less than or equal to other.
|
|
316
|
+
|
|
317
|
+
Args:
|
|
318
|
+
other: the other date, expected to be greater than or equal to val
|
|
319
|
+
|
|
320
|
+
Examples:
|
|
321
|
+
Usage::
|
|
322
|
+
|
|
323
|
+
assert_that(1).is_less_than_or_equal_to(0)
|
|
324
|
+
assert_that(1).is_less_than_or_equal_to(1)
|
|
325
|
+
assert_that(123.4).is_less_than_or_equal_to(100.0)
|
|
326
|
+
|
|
327
|
+
For dates, behavior is identical to :meth:`~assertpy.date.DateMixin.is_before` *except* when equal::
|
|
328
|
+
|
|
329
|
+
import datetime
|
|
330
|
+
|
|
331
|
+
today = datetime.datetime.now()
|
|
332
|
+
yesterday = today - datetime.timedelta(days=1)
|
|
333
|
+
|
|
334
|
+
assert_that(yesterday).is_less_than_or_equal_to(today)
|
|
335
|
+
assert_that(today).is_less_than_or_equal_to(today)
|
|
336
|
+
|
|
337
|
+
Returns:
|
|
338
|
+
AssertionBuilder: returns this instance to chain to the next assertion
|
|
339
|
+
|
|
340
|
+
Raises:
|
|
341
|
+
AssertionError: if val is **not** less than or equal to other
|
|
342
|
+
"""
|
|
343
|
+
self._validate_compareable(other)
|
|
344
|
+
if self.val > other:
|
|
345
|
+
if type(self.val) is datetime.datetime:
|
|
346
|
+
return self.error(
|
|
347
|
+
"Expected <%s> to be less than or equal to <%s>, but was not."
|
|
348
|
+
% (self.val.strftime("%Y-%m-%d %H:%M:%S"), other.strftime("%Y-%m-%d %H:%M:%S"))
|
|
349
|
+
)
|
|
350
|
+
else:
|
|
351
|
+
return self.error("Expected <%s> to be less than or equal to <%s>, but was not." % (self.val, other))
|
|
352
|
+
return self
|
|
353
|
+
|
|
354
|
+
def is_positive(self) -> Self:
|
|
355
|
+
"""Asserts that val is numeric and is greater than zero.
|
|
356
|
+
|
|
357
|
+
Examples:
|
|
358
|
+
Usage::
|
|
359
|
+
|
|
360
|
+
assert_that(1).is_positive()
|
|
361
|
+
assert_that(123.4).is_positive()
|
|
362
|
+
|
|
363
|
+
Returns:
|
|
364
|
+
AssertionBuilder: returns this instance to chain to the next assertion
|
|
365
|
+
|
|
366
|
+
Raises:
|
|
367
|
+
AssertionError: if val is **not** positive
|
|
368
|
+
"""
|
|
369
|
+
return self.is_greater_than(0)
|
|
370
|
+
|
|
371
|
+
def is_negative(self) -> Self:
|
|
372
|
+
"""Asserts that val is numeric and is less than zero.
|
|
373
|
+
|
|
374
|
+
Examples:
|
|
375
|
+
Usage::
|
|
376
|
+
|
|
377
|
+
assert_that(-1).is_negative()
|
|
378
|
+
assert_that(-123.4).is_negative()
|
|
379
|
+
|
|
380
|
+
Returns:
|
|
381
|
+
AssertionBuilder: returns this instance to chain to the next assertion
|
|
382
|
+
|
|
383
|
+
Raises:
|
|
384
|
+
AssertionError: if val is **not** negative
|
|
385
|
+
"""
|
|
386
|
+
return self.is_less_than(0)
|
|
387
|
+
|
|
388
|
+
def is_between(self, low, high) -> Self:
|
|
389
|
+
"""Asserts that val is numeric and is between low and high.
|
|
390
|
+
|
|
391
|
+
Args:
|
|
392
|
+
low: the low value
|
|
393
|
+
high: the high value
|
|
394
|
+
|
|
395
|
+
Examples:
|
|
396
|
+
Usage::
|
|
397
|
+
|
|
398
|
+
assert_that(1).is_between(0, 2)
|
|
399
|
+
assert_that(123.4).is_between(111.1, 222.2)
|
|
400
|
+
|
|
401
|
+
For dates, works as expected::
|
|
402
|
+
|
|
403
|
+
import datetime
|
|
404
|
+
|
|
405
|
+
today = datetime.datetime.now()
|
|
406
|
+
middle = today - datetime.timedelta(hours=12)
|
|
407
|
+
yesterday = today - datetime.timedelta(days=1)
|
|
408
|
+
|
|
409
|
+
assert_that(middle).is_between(yesterday, today)
|
|
410
|
+
|
|
411
|
+
Returns:
|
|
412
|
+
AssertionBuilder: returns this instance to chain to the next assertion
|
|
413
|
+
|
|
414
|
+
Raises:
|
|
415
|
+
AssertionError: if val is **not** between low and high
|
|
416
|
+
"""
|
|
417
|
+
val_type = type(self.val)
|
|
418
|
+
self._validate_between_args(val_type, low, high)
|
|
419
|
+
|
|
420
|
+
if self.val < low or self.val > high:
|
|
421
|
+
if val_type is datetime.datetime:
|
|
422
|
+
return self.error(
|
|
423
|
+
"Expected <%s> to be between <%s> and <%s>, but was not."
|
|
424
|
+
% (
|
|
425
|
+
self.val.strftime("%Y-%m-%d %H:%M:%S"),
|
|
426
|
+
low.strftime("%Y-%m-%d %H:%M:%S"),
|
|
427
|
+
high.strftime("%Y-%m-%d %H:%M:%S"),
|
|
428
|
+
)
|
|
429
|
+
)
|
|
430
|
+
else:
|
|
431
|
+
return self.error("Expected <%s> to be between <%s> and <%s>, but was not." % (self.val, low, high))
|
|
432
|
+
return self
|
|
433
|
+
|
|
434
|
+
def is_not_between(self, low, high) -> Self:
|
|
435
|
+
"""Asserts that val is numeric and is *not* between low and high.
|
|
436
|
+
|
|
437
|
+
Args:
|
|
438
|
+
low: the low value
|
|
439
|
+
high: the high value
|
|
440
|
+
|
|
441
|
+
Examples:
|
|
442
|
+
Usage::
|
|
443
|
+
|
|
444
|
+
assert_that(1).is_not_between(2, 3)
|
|
445
|
+
assert_that(1.1).is_not_between(2.2, 3.3)
|
|
446
|
+
|
|
447
|
+
Returns:
|
|
448
|
+
AssertionBuilder: returns this instance to chain to the next assertion
|
|
449
|
+
|
|
450
|
+
Raises:
|
|
451
|
+
AssertionError: if val **is** between low and high
|
|
452
|
+
"""
|
|
453
|
+
val_type = type(self.val)
|
|
454
|
+
self._validate_between_args(val_type, low, high)
|
|
455
|
+
|
|
456
|
+
if self.val >= low and self.val <= high:
|
|
457
|
+
if val_type is datetime.datetime:
|
|
458
|
+
return self.error(
|
|
459
|
+
"Expected <%s> to not be between <%s> and <%s>, but was."
|
|
460
|
+
% (
|
|
461
|
+
self.val.strftime("%Y-%m-%d %H:%M:%S"),
|
|
462
|
+
low.strftime("%Y-%m-%d %H:%M:%S"),
|
|
463
|
+
high.strftime("%Y-%m-%d %H:%M:%S"),
|
|
464
|
+
)
|
|
465
|
+
)
|
|
466
|
+
else:
|
|
467
|
+
return self.error("Expected <%s> to not be between <%s> and <%s>, but was." % (self.val, low, high))
|
|
468
|
+
return self
|
|
469
|
+
|
|
470
|
+
def is_close_to(self, other, tolerance) -> Self:
|
|
471
|
+
"""Asserts that val is numeric and is close to other within tolerance.
|
|
472
|
+
|
|
473
|
+
Args:
|
|
474
|
+
other: the other value, expected to be close to val within tolerance
|
|
475
|
+
tolerance: the tolerance
|
|
476
|
+
|
|
477
|
+
Examples:
|
|
478
|
+
Usage::
|
|
479
|
+
|
|
480
|
+
assert_that(123).is_close_to(100, 25)
|
|
481
|
+
assert_that(123.4).is_close_to(123, 0.5)
|
|
482
|
+
|
|
483
|
+
For dates, works as expected::
|
|
484
|
+
|
|
485
|
+
import datetime
|
|
486
|
+
|
|
487
|
+
today = datetime.datetime.now()
|
|
488
|
+
yesterday = today - datetime.timedelta(days=1)
|
|
489
|
+
|
|
490
|
+
assert_that(today).is_close_to(yesterday, datetime.timedelta(hours=36))
|
|
491
|
+
|
|
492
|
+
Returns:
|
|
493
|
+
AssertionBuilder: returns this instance to chain to the next assertion
|
|
494
|
+
|
|
495
|
+
Raises:
|
|
496
|
+
AssertionError: if val is **not** close to other within tolerance
|
|
497
|
+
"""
|
|
498
|
+
self._validate_close_to_args(self.val, other, tolerance)
|
|
499
|
+
|
|
500
|
+
if type(self.val) is not datetime.datetime and (math.isnan(self.val) or math.isnan(other)):
|
|
501
|
+
return self.error(
|
|
502
|
+
"Expected <%s> to be close to <%s> within tolerance <%s>, but was not." % (self.val, other, tolerance)
|
|
503
|
+
)
|
|
504
|
+
if self.val < (other - tolerance) or self.val > (other + tolerance):
|
|
505
|
+
if type(self.val) is datetime.datetime:
|
|
506
|
+
tolerance_seconds = tolerance.days * 86400 + tolerance.seconds + tolerance.microseconds / 1000000
|
|
507
|
+
h, rem = divmod(tolerance_seconds, 3600)
|
|
508
|
+
m, s = divmod(rem, 60)
|
|
509
|
+
return self.error(
|
|
510
|
+
"Expected <%s> to be close to <%s> within tolerance <%d:%02d:%02d>, but was not."
|
|
511
|
+
% (self.val.strftime("%Y-%m-%d %H:%M:%S"), other.strftime("%Y-%m-%d %H:%M:%S"), h, m, s)
|
|
512
|
+
)
|
|
513
|
+
else:
|
|
514
|
+
return self.error(
|
|
515
|
+
"Expected <%s> to be close to <%s> within tolerance <%s>, but was not."
|
|
516
|
+
% (self.val, other, tolerance)
|
|
517
|
+
)
|
|
518
|
+
return self
|
|
519
|
+
|
|
520
|
+
def is_not_close_to(self, other, tolerance) -> Self:
|
|
521
|
+
"""Asserts that val is numeric and is *not* close to other within tolerance.
|
|
522
|
+
|
|
523
|
+
Args:
|
|
524
|
+
other: the other value
|
|
525
|
+
tolerance: the tolerance
|
|
526
|
+
|
|
527
|
+
Examples:
|
|
528
|
+
Usage::
|
|
529
|
+
|
|
530
|
+
assert_that(123).is_not_close_to(100, 22)
|
|
531
|
+
assert_that(123.4).is_not_close_to(123, 0.1)
|
|
532
|
+
|
|
533
|
+
Returns:
|
|
534
|
+
AssertionBuilder: returns this instance to chain to the next assertion
|
|
535
|
+
|
|
536
|
+
Raises:
|
|
537
|
+
AssertionError: if val **is** close to other within tolerance
|
|
538
|
+
"""
|
|
539
|
+
self._validate_close_to_args(self.val, other, tolerance)
|
|
540
|
+
|
|
541
|
+
if self.val >= (other - tolerance) and self.val <= (other + tolerance):
|
|
542
|
+
if type(self.val) is datetime.datetime:
|
|
543
|
+
tolerance_seconds = tolerance.days * 86400 + tolerance.seconds + tolerance.microseconds / 1000000
|
|
544
|
+
h, rem = divmod(tolerance_seconds, 3600)
|
|
545
|
+
m, s = divmod(rem, 60)
|
|
546
|
+
return self.error(
|
|
547
|
+
"Expected <%s> to not be close to <%s> within tolerance <%d:%02d:%02d>, but was."
|
|
548
|
+
% (self.val.strftime("%Y-%m-%d %H:%M:%S"), other.strftime("%Y-%m-%d %H:%M:%S"), h, m, s)
|
|
549
|
+
)
|
|
550
|
+
else:
|
|
551
|
+
return self.error(
|
|
552
|
+
"Expected <%s> to not be close to <%s> within tolerance <%s>, but was."
|
|
553
|
+
% (self.val, other, tolerance)
|
|
554
|
+
)
|
|
555
|
+
return self
|
assertpy2/py.typed
ADDED
|
File without changes
|