encommon 0.7.6__py3-none-any.whl → 0.8.1__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.
- encommon/config/__init__.py +6 -0
- encommon/config/common.py +18 -14
- encommon/config/config.py +21 -14
- encommon/config/files.py +13 -7
- encommon/config/logger.py +94 -88
- encommon/config/params.py +4 -4
- encommon/config/paths.py +16 -8
- encommon/config/test/test_common.py +27 -4
- encommon/config/test/test_config.py +48 -82
- encommon/config/test/test_files.py +58 -43
- encommon/config/test/test_logger.py +129 -82
- encommon/config/test/test_paths.py +70 -30
- encommon/conftest.py +52 -12
- encommon/crypts/__init__.py +2 -0
- encommon/crypts/crypts.py +3 -1
- encommon/crypts/hashes.py +2 -2
- encommon/crypts/test/test_crypts.py +50 -28
- encommon/crypts/test/test_hashes.py +20 -18
- encommon/times/__init__.py +2 -0
- encommon/times/common.py +99 -15
- encommon/times/duration.py +50 -36
- encommon/times/parse.py +13 -25
- encommon/times/test/test_common.py +47 -16
- encommon/times/test/test_duration.py +104 -79
- encommon/times/test/test_parse.py +53 -63
- encommon/times/test/test_timers.py +90 -36
- encommon/times/test/test_times.py +21 -30
- encommon/times/test/test_window.py +73 -21
- encommon/times/timers.py +91 -58
- encommon/times/times.py +36 -34
- encommon/times/window.py +4 -4
- encommon/types/dicts.py +10 -4
- encommon/types/empty.py +7 -2
- encommon/types/strings.py +10 -0
- encommon/types/test/test_dicts.py +5 -5
- encommon/types/test/test_empty.py +4 -1
- encommon/types/test/test_strings.py +1 -1
- encommon/utils/__init__.py +4 -0
- encommon/utils/common.py +51 -6
- encommon/utils/match.py +5 -4
- encommon/utils/paths.py +42 -23
- encommon/utils/sample.py +31 -27
- encommon/utils/stdout.py +28 -17
- encommon/utils/test/test_common.py +35 -0
- encommon/utils/test/test_paths.py +3 -2
- encommon/utils/test/test_sample.py +28 -12
- encommon/version.txt +1 -1
- {encommon-0.7.6.dist-info → encommon-0.8.1.dist-info}/METADATA +1 -1
- encommon-0.8.1.dist-info/RECORD +63 -0
- encommon-0.7.6.dist-info/RECORD +0 -62
- {encommon-0.7.6.dist-info → encommon-0.8.1.dist-info}/LICENSE +0 -0
- {encommon-0.7.6.dist-info → encommon-0.8.1.dist-info}/WHEEL +0 -0
- {encommon-0.7.6.dist-info → encommon-0.8.1.dist-info}/top_level.txt +0 -0
encommon/times/duration.py
CHANGED
@@ -11,6 +11,10 @@ from typing import Literal
|
|
11
11
|
from typing import Union
|
12
12
|
from typing import get_args
|
13
13
|
|
14
|
+
from ..types.strings import COMMAS
|
15
|
+
from ..types.strings import SEMPTY
|
16
|
+
from ..types.strings import SPACED
|
17
|
+
|
14
18
|
|
15
19
|
|
16
20
|
DURAGROUP = Literal[
|
@@ -33,7 +37,7 @@ DURAUNITS = Union[
|
|
33
37
|
|
34
38
|
class Duration:
|
35
39
|
"""
|
36
|
-
Convert provided
|
40
|
+
Convert the provided seconds in a human friendly format.
|
37
41
|
|
38
42
|
Example
|
39
43
|
-------
|
@@ -52,8 +56,8 @@ class Duration:
|
|
52
56
|
|
53
57
|
:param seconds: Period in seconds that will be iterated.
|
54
58
|
:param smart: Determines if we hide seconds after minute.
|
55
|
-
:param groups: Determine the
|
56
|
-
ensuring
|
59
|
+
:param groups: Determine the quantity of groups to show,
|
60
|
+
ensuring larger units are returned before smaller.
|
57
61
|
"""
|
58
62
|
|
59
63
|
__source: float
|
@@ -122,7 +126,7 @@ class Duration:
|
|
122
126
|
"""
|
123
127
|
Built-in method representing numeric value for instance.
|
124
128
|
|
125
|
-
:returns: Numeric representation for
|
129
|
+
:returns: Numeric representation for value in instance.
|
126
130
|
"""
|
127
131
|
|
128
132
|
return int(self.__source)
|
@@ -134,7 +138,7 @@ class Duration:
|
|
134
138
|
"""
|
135
139
|
Built-in method representing numeric value for instance.
|
136
140
|
|
137
|
-
:returns: Numeric representation for
|
141
|
+
:returns: Numeric representation for value in instance.
|
138
142
|
"""
|
139
143
|
|
140
144
|
return float(self.__source)
|
@@ -326,7 +330,7 @@ class Duration:
|
|
326
330
|
source = self.__source
|
327
331
|
seconds = int(source)
|
328
332
|
|
329
|
-
|
333
|
+
units: dict[DURAUNITS, int] = {}
|
330
334
|
|
331
335
|
groups: dict[DURAGROUP, int] = {
|
332
336
|
'year': 31536000,
|
@@ -337,60 +341,67 @@ class Duration:
|
|
337
341
|
'minute': 60}
|
338
342
|
|
339
343
|
|
340
|
-
|
344
|
+
items = groups.items()
|
345
|
+
|
346
|
+
for key, value in items:
|
341
347
|
|
342
348
|
if seconds < value:
|
343
349
|
continue
|
344
350
|
|
345
351
|
_value = seconds // value
|
346
|
-
|
347
|
-
returned[key] = _value
|
348
|
-
|
349
352
|
seconds %= value
|
350
353
|
|
354
|
+
units[key] = _value
|
355
|
+
|
351
356
|
|
352
|
-
if (
|
353
|
-
|
354
|
-
|
355
|
-
|
357
|
+
if ((seconds >= 1
|
358
|
+
and source > 60)
|
359
|
+
or source < 60):
|
360
|
+
units['second'] = seconds
|
356
361
|
|
357
|
-
if (
|
358
|
-
and
|
359
|
-
and
|
360
|
-
del
|
362
|
+
if ('second' in units
|
363
|
+
and len(units) >= 2
|
364
|
+
and self.__smart):
|
365
|
+
del units['second']
|
361
366
|
|
362
367
|
|
363
|
-
|
364
|
-
list(
|
368
|
+
_groups = (
|
369
|
+
list(units.items())
|
365
370
|
[:self.__groups])
|
366
371
|
|
367
372
|
if short is False:
|
368
|
-
return dict(
|
373
|
+
return dict(_groups)
|
369
374
|
|
370
375
|
return {
|
371
376
|
DURAMAPS[k]: v
|
372
|
-
for k, v in
|
377
|
+
for k, v in _groups}
|
373
378
|
|
374
379
|
|
375
380
|
def __duration(
|
376
381
|
self,
|
377
|
-
delim: str =
|
382
|
+
delim: str = SPACED,
|
378
383
|
short: bool = True,
|
379
384
|
) -> str:
|
380
385
|
"""
|
381
|
-
Return the compact format
|
386
|
+
Return the compact format determined by source duration.
|
382
387
|
|
383
388
|
:param delim: Optional delimiter for between the groups.
|
384
389
|
:param short: Determine if we should use the short hand.
|
385
|
-
:returns: Compact format
|
390
|
+
:returns: Compact format determined by source duration.
|
386
391
|
"""
|
387
392
|
|
388
393
|
parts: list[str] = []
|
389
394
|
|
390
395
|
groups = self.units(short)
|
391
|
-
spaced = '' if short else ' '
|
392
396
|
|
393
|
-
|
397
|
+
space = (
|
398
|
+
SEMPTY if short
|
399
|
+
else SPACED)
|
400
|
+
|
401
|
+
|
402
|
+
items = groups.items()
|
403
|
+
|
404
|
+
for part, value in items:
|
394
405
|
|
395
406
|
unit: str = part
|
396
407
|
|
@@ -399,7 +410,8 @@ class Duration:
|
|
399
410
|
unit += 's'
|
400
411
|
|
401
412
|
parts.append(
|
402
|
-
f'{value}{
|
413
|
+
f'{value}{space}{unit}')
|
414
|
+
|
403
415
|
|
404
416
|
return delim.join(parts)
|
405
417
|
|
@@ -409,9 +421,9 @@ class Duration:
|
|
409
421
|
self,
|
410
422
|
) -> str:
|
411
423
|
"""
|
412
|
-
Return the compact format
|
424
|
+
Return the compact format determined by source duration.
|
413
425
|
|
414
|
-
:returns: Compact format
|
426
|
+
:returns: Compact format determined by source duration.
|
415
427
|
"""
|
416
428
|
|
417
429
|
return self.__duration()
|
@@ -422,12 +434,13 @@ class Duration:
|
|
422
434
|
self,
|
423
435
|
) -> str:
|
424
436
|
"""
|
425
|
-
Return the compact format
|
437
|
+
Return the compact format determined by source duration.
|
426
438
|
|
427
|
-
:returns: Compact format
|
439
|
+
:returns: Compact format determined by source duration.
|
428
440
|
"""
|
429
441
|
|
430
|
-
return self.short.replace(
|
442
|
+
return self.short.replace(
|
443
|
+
SPACED, SEMPTY)
|
431
444
|
|
432
445
|
|
433
446
|
@property
|
@@ -435,12 +448,13 @@ class Duration:
|
|
435
448
|
self,
|
436
449
|
) -> str:
|
437
450
|
"""
|
438
|
-
Return the verbose format
|
451
|
+
Return the verbose format determined by source duration.
|
439
452
|
|
440
|
-
:returns:
|
453
|
+
:returns: Verbose format determined by source duration.
|
441
454
|
"""
|
442
455
|
|
443
456
|
if self.__source < 60:
|
444
457
|
return 'just now'
|
445
458
|
|
446
|
-
return self.__duration(
|
459
|
+
return self.__duration(
|
460
|
+
COMMAS, False)
|
encommon/times/parse.py
CHANGED
@@ -15,7 +15,6 @@ from typing import Optional
|
|
15
15
|
from typing import TYPE_CHECKING
|
16
16
|
|
17
17
|
from dateutil import parser
|
18
|
-
from dateutil.tz import gettz
|
19
18
|
|
20
19
|
from snaptime import snap
|
21
20
|
|
@@ -23,6 +22,7 @@ from .common import NUMERISH
|
|
23
22
|
from .common import PARSABLE
|
24
23
|
from .common import SNAPABLE
|
25
24
|
from .common import STRINGNOW
|
25
|
+
from .common import findtz
|
26
26
|
from .common import strptime
|
27
27
|
from .common import utcdatetime
|
28
28
|
|
@@ -87,14 +87,7 @@ def parse_time( # noqa: CFQ004
|
|
87
87
|
and re_match(NUMERISH, source)):
|
88
88
|
source = float(source)
|
89
89
|
|
90
|
-
|
91
|
-
if tzname is not None:
|
92
|
-
tzinfo = gettz(tzname)
|
93
|
-
else:
|
94
|
-
tzinfo = timezone.utc
|
95
|
-
|
96
|
-
if tzinfo is None:
|
97
|
-
raise ValueError('tzname')
|
90
|
+
tzinfo = findtz(tzname)
|
98
91
|
|
99
92
|
|
100
93
|
if isinstance(source, (int, float)):
|
@@ -129,7 +122,7 @@ def parse_time( # noqa: CFQ004
|
|
129
122
|
.astimezone(timezone.utc))
|
130
123
|
|
131
124
|
|
132
|
-
raise ValueError('source')
|
125
|
+
raise ValueError('source') # NOCVR
|
133
126
|
|
134
127
|
|
135
128
|
|
@@ -159,13 +152,10 @@ def shift_time(
|
|
159
152
|
:returns: Python datetime object containing related time.
|
160
153
|
"""
|
161
154
|
|
162
|
-
anchor = parse_time(
|
163
|
-
|
164
|
-
parsed = snap(anchor, notate)
|
165
|
-
|
166
|
-
assert isinstance(parsed, datetime)
|
155
|
+
anchor = parse_time(
|
156
|
+
anchor, tzname=tzname)
|
167
157
|
|
168
|
-
return
|
158
|
+
return snap(anchor, notate)
|
169
159
|
|
170
160
|
|
171
161
|
|
@@ -195,18 +185,14 @@ def string_time(
|
|
195
185
|
:returns: Python datetime object containing related time.
|
196
186
|
"""
|
197
187
|
|
198
|
-
parsed: Optional[datetime] = None
|
199
|
-
|
200
188
|
if formats is not None:
|
201
189
|
with suppress(ValueError):
|
202
|
-
|
203
|
-
|
204
|
-
if parsed is None:
|
205
|
-
parsed = parser.parse(source)
|
190
|
+
return strptime(source, formats)
|
206
191
|
|
207
|
-
|
192
|
+
parsed = parser.parse(source)
|
208
193
|
|
209
|
-
return parse_time(
|
194
|
+
return parse_time(
|
195
|
+
parsed, tzname=tzname)
|
210
196
|
|
211
197
|
|
212
198
|
|
@@ -234,4 +220,6 @@ def since_time(
|
|
234
220
|
|
235
221
|
delta = stop - start
|
236
222
|
|
237
|
-
|
223
|
+
since = delta.total_seconds()
|
224
|
+
|
225
|
+
return abs(since)
|
@@ -11,6 +11,9 @@ from dateutil.tz import gettz
|
|
11
11
|
|
12
12
|
from pytest import raises
|
13
13
|
|
14
|
+
from ..common import STAMP_SIMPLE
|
15
|
+
from ..common import UNIXEPOCH
|
16
|
+
from ..common import findtz
|
14
17
|
from ..common import strptime
|
15
18
|
from ..common import utcdatetime
|
16
19
|
|
@@ -28,6 +31,8 @@ def test_utcdatetime() -> None:
|
|
28
31
|
assert dtime.month == 1
|
29
32
|
assert dtime.day == 1
|
30
33
|
assert dtime.hour == 0
|
34
|
+
assert dtime.minute == 0
|
35
|
+
assert dtime.second == 0
|
31
36
|
|
32
37
|
|
33
38
|
dtime = utcdatetime(
|
@@ -38,41 +43,67 @@ def test_utcdatetime() -> None:
|
|
38
43
|
assert dtime.month == 1
|
39
44
|
assert dtime.day == 1
|
40
45
|
assert dtime.hour == 6
|
46
|
+
assert dtime.minute == 0
|
47
|
+
assert dtime.second == 0
|
41
48
|
|
42
49
|
|
43
|
-
assert utcdatetime().year >= 2023
|
44
50
|
|
51
|
+
def test_strptime() -> None:
|
52
|
+
"""
|
53
|
+
Perform various tests associated with relevant routines.
|
54
|
+
"""
|
45
55
|
|
46
56
|
|
47
|
-
|
57
|
+
parsed = strptime(
|
58
|
+
UNIXEPOCH, STAMP_SIMPLE)
|
59
|
+
|
60
|
+
assert parsed.year == 1970
|
61
|
+
assert parsed.month == 1
|
62
|
+
assert parsed.day == 1
|
63
|
+
assert parsed.hour == 0
|
64
|
+
assert parsed.minute == 0
|
65
|
+
assert parsed.second == 0
|
66
|
+
|
67
|
+
|
68
|
+
|
69
|
+
def test_strptime_raises() -> None:
|
48
70
|
"""
|
49
71
|
Perform various tests associated with relevant routines.
|
50
72
|
"""
|
51
73
|
|
74
|
+
_raises = raises(ValueError)
|
52
75
|
|
53
|
-
|
76
|
+
with _raises as reason:
|
77
|
+
strptime('foo', '%Y')
|
54
78
|
|
55
|
-
|
56
|
-
assert dtime.month == 1
|
57
|
-
assert dtime.day == 1
|
58
|
-
assert dtime.hour == 0
|
79
|
+
_reason = str(reason.value)
|
59
80
|
|
81
|
+
assert _reason == 'invalid'
|
60
82
|
|
61
|
-
dtime = strptime('1970', ['%Y'])
|
62
83
|
|
63
|
-
assert dtime.year == 1970
|
64
|
-
assert dtime.month == 1
|
65
|
-
assert dtime.day == 1
|
66
|
-
assert dtime.hour == 0
|
67
84
|
|
85
|
+
def test_findtz() -> None:
|
86
|
+
"""
|
87
|
+
Perform various tests associated with relevant routines.
|
88
|
+
"""
|
68
89
|
|
69
90
|
|
70
|
-
|
91
|
+
tzinfo = findtz('UTC')
|
92
|
+
|
93
|
+
assert 'UTC' in str(tzinfo)
|
94
|
+
|
95
|
+
|
96
|
+
|
97
|
+
def test_findtz_raises() -> None:
|
71
98
|
"""
|
72
99
|
Perform various tests associated with relevant routines.
|
73
100
|
"""
|
74
101
|
|
75
|
-
|
76
|
-
|
102
|
+
_raises = raises(ValueError)
|
103
|
+
|
104
|
+
with _raises as reason:
|
105
|
+
findtz('foo')
|
106
|
+
|
107
|
+
_reason = str(reason.value)
|
77
108
|
|
78
|
-
assert
|
109
|
+
assert _reason == 'tzname'
|
@@ -8,6 +8,7 @@ is permitted, for more information consult the project license file.
|
|
8
8
|
|
9
9
|
|
10
10
|
from ..duration import Duration
|
11
|
+
from ...types.strings import COMMAS
|
11
12
|
|
12
13
|
|
13
14
|
|
@@ -16,9 +17,10 @@ def test_Duration() -> None:
|
|
16
17
|
Perform various tests associated with relevant routines.
|
17
18
|
"""
|
18
19
|
|
19
|
-
|
20
|
+
durate = Duration(95401)
|
20
21
|
|
21
|
-
|
22
|
+
|
23
|
+
attrs = list(durate.__dict__)
|
22
24
|
|
23
25
|
assert attrs == [
|
24
26
|
'_Duration__source',
|
@@ -26,91 +28,94 @@ def test_Duration() -> None:
|
|
26
28
|
'_Duration__groups']
|
27
29
|
|
28
30
|
|
29
|
-
assert repr(
|
30
|
-
'Duration('
|
31
|
-
'seconds=95401.0, '
|
32
|
-
'smart=True, '
|
33
|
-
'groups=7)')
|
31
|
+
assert repr(durate)[:23] == (
|
32
|
+
'Duration(seconds=95401.')
|
34
33
|
|
35
|
-
assert
|
36
|
-
assert str(duration) == '1d2h30m'
|
34
|
+
assert hash(durate) > 0
|
37
35
|
|
36
|
+
assert str(durate) == '1d2h30m'
|
38
37
|
|
39
|
-
assert int(duration) == 95401
|
40
|
-
assert float(duration) == 95401
|
41
38
|
|
42
|
-
assert
|
43
|
-
assert
|
44
|
-
assert duration - 1 == 95400
|
45
|
-
assert duration - duration == 0
|
39
|
+
assert int(durate) == 95401
|
40
|
+
assert float(durate) == 95401
|
46
41
|
|
47
|
-
assert
|
48
|
-
assert
|
49
|
-
assert
|
42
|
+
assert durate + 1 == 95402
|
43
|
+
assert durate + durate == 190802
|
44
|
+
assert durate - 1 == 95400
|
45
|
+
assert durate - durate == 0
|
50
46
|
|
51
|
-
assert
|
52
|
-
assert
|
53
|
-
assert
|
54
|
-
assert duration <= Duration(95401)
|
47
|
+
assert durate == durate
|
48
|
+
assert durate != Duration(60)
|
49
|
+
assert durate != 'invalid'
|
55
50
|
|
51
|
+
assert durate > Duration(95400)
|
52
|
+
assert durate >= Duration(95401)
|
53
|
+
assert durate < Duration(95402)
|
54
|
+
assert durate <= Duration(95401)
|
56
55
|
|
57
|
-
assert duration.source == 95401
|
58
|
-
assert duration.smart is True
|
59
|
-
assert duration.groups == 7
|
60
56
|
|
61
|
-
assert
|
62
|
-
|
63
|
-
assert
|
64
|
-
'1 day, 2 hours, 30 minutes')
|
57
|
+
assert durate.source == 95401
|
58
|
+
|
59
|
+
assert durate.smart is True
|
65
60
|
|
66
|
-
assert
|
61
|
+
assert durate.groups == 7
|
62
|
+
|
63
|
+
assert durate.units() == {
|
67
64
|
'day': 1,
|
68
65
|
'hour': 2,
|
69
66
|
'minute': 30}
|
70
67
|
|
68
|
+
assert durate.short == '1d 2h 30m'
|
69
|
+
|
70
|
+
assert durate.compact == '1d2h30m'
|
71
|
+
|
72
|
+
assert durate.verbose == (
|
73
|
+
'1 day, 2 hours, 30 minutes')
|
74
|
+
|
75
|
+
|
71
76
|
|
72
|
-
|
77
|
+
def test_Duration_cover() -> None:
|
78
|
+
"""
|
79
|
+
Perform various tests associated with relevant routines.
|
80
|
+
"""
|
81
|
+
|
82
|
+
durate = Duration(
|
73
83
|
seconds=7501,
|
74
84
|
smart=False)
|
75
85
|
|
76
|
-
assert
|
77
|
-
assert
|
78
|
-
assert
|
86
|
+
assert durate.short == '2h 5m 1s'
|
87
|
+
assert durate.compact == '2h5m1s'
|
88
|
+
assert durate.verbose == (
|
79
89
|
'2 hours, 5 minutes, 1 second')
|
80
90
|
|
81
91
|
|
82
|
-
|
92
|
+
durate = Duration(
|
93
|
+
groups=3,
|
83
94
|
seconds=694800,
|
84
|
-
smart=False
|
85
|
-
groups=3)
|
95
|
+
smart=False)
|
86
96
|
|
87
|
-
assert
|
88
|
-
assert
|
89
|
-
assert
|
97
|
+
assert durate.short == '1w 1d 1h'
|
98
|
+
assert durate.compact == '1w1d1h'
|
99
|
+
assert durate.verbose == (
|
90
100
|
'1 week, 1 day, 1 hour')
|
91
101
|
|
92
102
|
|
93
|
-
|
103
|
+
durate = Duration(36295261)
|
94
104
|
|
95
|
-
|
96
|
-
|
97
|
-
'week': 3,
|
98
|
-
'month': 1,
|
99
|
-
'
|
100
|
-
'hour': 2,
|
101
|
-
'minute': 1}
|
105
|
+
units = durate.units(False)
|
106
|
+
assert units == {
|
107
|
+
'year': 1, 'week': 3,
|
108
|
+
'month': 1, 'day': 4,
|
109
|
+
'hour': 2, 'minute': 1}
|
102
110
|
|
103
|
-
|
104
|
-
|
105
|
-
'w': 3,
|
106
|
-
'
|
107
|
-
'd': 4,
|
108
|
-
'h': 2,
|
109
|
-
'm': 1}
|
111
|
+
units = durate.units(True)
|
112
|
+
assert units == {
|
113
|
+
'y': 1, 'w': 3, 'mon': 1,
|
114
|
+
'd': 4, 'h': 2, 'm': 1}
|
110
115
|
|
111
116
|
|
112
117
|
|
113
|
-
def
|
118
|
+
def test_Duration_iterate() -> None:
|
114
119
|
"""
|
115
120
|
Perform various tests associated with relevant routines.
|
116
121
|
"""
|
@@ -126,52 +131,72 @@ def test_Duration_cover() -> None:
|
|
126
131
|
|
127
132
|
expects = {
|
128
133
|
|
129
|
-
year: (
|
130
|
-
|
134
|
+
year: (
|
135
|
+
'1y', '1 year'),
|
136
|
+
year + 1: (
|
137
|
+
'1y', '1 year'),
|
131
138
|
year - 1: (
|
132
139
|
'12mon4d23h59m',
|
133
140
|
'12 months, 4 days'),
|
134
141
|
|
135
|
-
quarter: (
|
136
|
-
|
142
|
+
quarter: (
|
143
|
+
'3mon', '3 months'),
|
144
|
+
quarter + 1: (
|
145
|
+
'3mon', '3 months'),
|
137
146
|
quarter - 1: (
|
138
147
|
'2mon4w1d23h59m',
|
139
148
|
'2 months, 4 weeks'),
|
140
149
|
|
141
|
-
month: (
|
142
|
-
|
150
|
+
month: (
|
151
|
+
'1mon', '1 month'),
|
152
|
+
month + 1: (
|
153
|
+
'1mon', '1 month'),
|
143
154
|
month - 1: (
|
144
155
|
'4w1d23h59m',
|
145
156
|
'4 weeks, 1 day'),
|
146
157
|
|
147
|
-
week: (
|
148
|
-
|
158
|
+
week: (
|
159
|
+
'1w', '1 week'),
|
160
|
+
week + 1: (
|
161
|
+
'1w', '1 week'),
|
149
162
|
week - 1: (
|
150
163
|
'6d23h59m',
|
151
164
|
'6 days, 23 hours'),
|
152
165
|
|
153
|
-
day: (
|
154
|
-
|
166
|
+
day: (
|
167
|
+
'1d', '1 day'),
|
168
|
+
day + 1: (
|
169
|
+
'1d', '1 day'),
|
155
170
|
day - 1: (
|
156
171
|
'23h59m',
|
157
172
|
'23 hours, 59 minutes'),
|
158
173
|
|
159
|
-
hour: (
|
160
|
-
|
161
|
-
hour
|
174
|
+
hour: (
|
175
|
+
'1h', '1 hour'),
|
176
|
+
hour + 1: (
|
177
|
+
'1h', '1 hour'),
|
178
|
+
hour - 1: (
|
179
|
+
'59m', '59 minutes'),
|
180
|
+
|
181
|
+
second: (
|
182
|
+
'1m', '1 minute'),
|
183
|
+
second + 1: (
|
184
|
+
'1m', '1 minute'),
|
185
|
+
second - 1: (
|
186
|
+
'59s', 'just now')}
|
162
187
|
|
163
|
-
second: ('1m', '1 minute'),
|
164
|
-
second + 1: ('1m', '1 minute'),
|
165
|
-
second - 1: ('59s', 'just now')}
|
166
188
|
|
189
|
+
items = expects.items()
|
167
190
|
|
168
|
-
for source, expect in
|
191
|
+
for source, expect in items:
|
169
192
|
|
170
|
-
|
171
|
-
assert duration.compact == expect[0]
|
193
|
+
durate = Duration(source)
|
172
194
|
|
173
|
-
|
174
|
-
|
175
|
-
|
195
|
+
compact, verbose = expect
|
196
|
+
_compact = durate.compact
|
197
|
+
_verbose = COMMAS.join(
|
198
|
+
durate.verbose
|
199
|
+
.split(', ')[:2])
|
176
200
|
|
177
|
-
assert
|
201
|
+
assert _compact == compact
|
202
|
+
assert _verbose == verbose
|