dycw-utilities 0.131.16__py3-none-any.whl → 0.131.17__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.
utilities/redis.py CHANGED
@@ -1,6 +1,5 @@
1
1
  from __future__ import annotations
2
2
 
3
- import asyncio
4
3
  from asyncio import CancelledError, Event, Queue, Task, create_task
5
4
  from collections.abc import AsyncIterator, Callable, Mapping
6
5
  from contextlib import asynccontextmanager, suppress
@@ -24,18 +23,13 @@ from typing import (
24
23
 
25
24
  from redis.asyncio import Redis
26
25
 
27
- from utilities.asyncio import EnhancedQueue, Looper, timeout_dur
26
+ from utilities.asyncio import EnhancedQueue, Looper, sleep_td, timeout_td
28
27
  from utilities.contextlib import suppress_super_object_attribute_error
29
- from utilities.datetime import (
30
- MILLISECOND,
31
- SECOND,
32
- datetime_duration_to_float,
33
- datetime_duration_to_timedelta,
34
- )
35
28
  from utilities.errors import ImpossibleCaseError
36
29
  from utilities.functions import ensure_int, identity
37
30
  from utilities.iterables import always_iterable, one
38
31
  from utilities.orjson import deserialize, serialize
32
+ from utilities.whenever2 import MILLISECOND, SECOND
39
33
 
40
34
  if TYPE_CHECKING:
41
35
  from collections.abc import (
@@ -51,9 +45,10 @@ if TYPE_CHECKING:
51
45
  from redis.asyncio import ConnectionPool
52
46
  from redis.asyncio.client import PubSub
53
47
  from redis.typing import EncodableT, ResponseT
48
+ from whenever import TimeDelta
54
49
 
55
50
  from utilities.iterables import MaybeIterable
56
- from utilities.types import Duration, MaybeType, TypeLike
51
+ from utilities.types import MaybeType, TypeLike
57
52
 
58
53
 
59
54
  _K = TypeVar("_K")
@@ -72,7 +67,7 @@ _V2 = TypeVar("_V2")
72
67
  _V3 = TypeVar("_V3")
73
68
 
74
69
 
75
- _PUBLISH_TIMEOUT: Duration = SECOND
70
+ _PUBLISH_TIMEOUT: TimeDelta = SECOND
76
71
 
77
72
 
78
73
  ##
@@ -89,17 +84,17 @@ class RedisHashMapKey(Generic[_K, _V]):
89
84
  value: TypeLike[_V]
90
85
  value_serializer: Callable[[_V], bytes] | None = None
91
86
  value_deserializer: Callable[[bytes], _V] | None = None
92
- timeout: Duration | None = None
87
+ timeout: TimeDelta | None = None
93
88
  error: MaybeType[BaseException] = TimeoutError
94
- ttl: Duration | None = None
89
+ ttl: TimeDelta | None = None
95
90
 
96
91
  async def delete(self, redis: Redis, key: _K, /) -> int:
97
92
  """Delete a key from a hashmap in `redis`."""
98
93
  ser = _serialize( # skipif-ci-and-not-linux
99
94
  key, serializer=self.key_serializer
100
95
  ).decode()
101
- async with timeout_dur( # skipif-ci-and-not-linux
102
- duration=self.timeout, error=self.error
96
+ async with timeout_td( # skipif-ci-and-not-linux
97
+ self.timeout, error=self.error
103
98
  ):
104
99
  return await cast("Awaitable[int]", redis.hdel(self.name, ser))
105
100
  raise ImpossibleCaseError(case=[f"{redis=}", f"{key=}"]) # pragma: no cover
@@ -109,8 +104,8 @@ class RedisHashMapKey(Generic[_K, _V]):
109
104
  ser = _serialize( # skipif-ci-and-not-linux
110
105
  key, serializer=self.key_serializer
111
106
  ).decode()
112
- async with timeout_dur( # skipif-ci-and-not-linux
113
- duration=self.timeout, error=self.error
107
+ async with timeout_td( # skipif-ci-and-not-linux
108
+ self.timeout, error=self.error
114
109
  ):
115
110
  return await cast("Awaitable[bool]", redis.hexists(self.name, ser))
116
111
 
@@ -123,8 +118,8 @@ class RedisHashMapKey(Generic[_K, _V]):
123
118
 
124
119
  async def get_all(self, redis: Redis, /) -> Mapping[_K, _V]:
125
120
  """Get a value from a hashmap in `redis`."""
126
- async with timeout_dur( # skipif-ci-and-not-linux
127
- duration=self.timeout, error=self.error
121
+ async with timeout_td( # skipif-ci-and-not-linux
122
+ self.timeout, error=self.error
128
123
  ):
129
124
  result = await cast( # skipif-ci-and-not-linux
130
125
  "Awaitable[Mapping[bytes, bytes]]", redis.hgetall(self.name)
@@ -146,8 +141,8 @@ class RedisHashMapKey(Generic[_K, _V]):
146
141
  ser = [ # skipif-ci-and-not-linux
147
142
  _serialize(key, serializer=self.key_serializer) for key in keys
148
143
  ]
149
- async with timeout_dur( # skipif-ci-and-not-linux
150
- duration=self.timeout, error=self.error
144
+ async with timeout_td( # skipif-ci-and-not-linux
145
+ self.timeout, error=self.error
151
146
  ):
152
147
  result = await cast( # skipif-ci-and-not-linux
153
148
  "Awaitable[Sequence[bytes | None]]", redis.hmget(self.name, ser)
@@ -161,8 +156,8 @@ class RedisHashMapKey(Generic[_K, _V]):
161
156
 
162
157
  async def keys(self, redis: Redis, /) -> Sequence[_K]:
163
158
  """Get the keys of a hashmap in `redis`."""
164
- async with timeout_dur( # skipif-ci-and-not-linux
165
- duration=self.timeout, error=self.error
159
+ async with timeout_td( # skipif-ci-and-not-linux
160
+ self.timeout, error=self.error
166
161
  ):
167
162
  result = await cast("Awaitable[Sequence[bytes]]", redis.hkeys(self.name))
168
163
  return [ # skipif-ci-and-not-linux
@@ -171,8 +166,8 @@ class RedisHashMapKey(Generic[_K, _V]):
171
166
 
172
167
  async def length(self, redis: Redis, /) -> int:
173
168
  """Get the length of a hashmap in `redis`."""
174
- async with timeout_dur( # skipif-ci-and-not-linux
175
- duration=self.timeout, error=self.error
169
+ async with timeout_td( # skipif-ci-and-not-linux
170
+ self.timeout, error=self.error
176
171
  ):
177
172
  return await cast("Awaitable[int]", redis.hlen(self.name))
178
173
 
@@ -190,20 +185,20 @@ class RedisHashMapKey(Generic[_K, _V]):
190
185
  )
191
186
  for key, value in mapping.items()
192
187
  }
193
- async with timeout_dur( # skipif-ci-and-not-linux
194
- duration=self.timeout, error=self.error
188
+ async with timeout_td( # skipif-ci-and-not-linux
189
+ self.timeout, error=self.error
195
190
  ):
196
191
  result = await cast(
197
192
  "Awaitable[int]", redis.hset(self.name, mapping=cast("Any", ser))
198
193
  )
199
194
  if self.ttl is not None:
200
- await redis.pexpire(self.name, datetime_duration_to_timedelta(self.ttl))
195
+ await redis.pexpire(self.name, self.ttl.py_timedelta())
201
196
  return result # skipif-ci-and-not-linux
202
197
 
203
198
  async def values(self, redis: Redis, /) -> Sequence[_V]:
204
199
  """Get the values of a hashmap in `redis`."""
205
- async with timeout_dur( # skipif-ci-and-not-linux
206
- duration=self.timeout, error=self.error
200
+ async with timeout_td( # skipif-ci-and-not-linux
201
+ self.timeout, error=self.error
207
202
  ):
208
203
  result = await cast("Awaitable[Sequence[bytes]]", redis.hvals(self.name))
209
204
  return [ # skipif-ci-and-not-linux
@@ -222,9 +217,9 @@ def redis_hash_map_key(
222
217
  key_deserializer: Callable[[bytes], Any] | None = None,
223
218
  value_serializer: Callable[[_V], bytes] | None = None,
224
219
  value_deserializer: Callable[[bytes], _V] | None = None,
225
- timeout: Duration | None = None,
220
+ timeout: TimeDelta | None = None,
226
221
  error: type[Exception] = TimeoutError,
227
- ttl: Duration | None = None,
222
+ ttl: TimeDelta | None = None,
228
223
  ) -> RedisHashMapKey[_K, _V]: ...
229
224
  @overload
230
225
  def redis_hash_map_key(
@@ -237,9 +232,9 @@ def redis_hash_map_key(
237
232
  key_deserializer: Callable[[bytes], Any] | None = None,
238
233
  value_serializer: Callable[[_V1 | _V2], bytes] | None = None,
239
234
  value_deserializer: Callable[[bytes], _V1 | _V2] | None = None,
240
- timeout: Duration | None = None,
235
+ timeout: TimeDelta | None = None,
241
236
  error: type[Exception] = TimeoutError,
242
- ttl: Duration | None = None,
237
+ ttl: TimeDelta | None = None,
243
238
  ) -> RedisHashMapKey[_K, _V1 | _V2]: ...
244
239
  @overload
245
240
  def redis_hash_map_key(
@@ -252,9 +247,9 @@ def redis_hash_map_key(
252
247
  key_deserializer: Callable[[bytes], Any] | None = None,
253
248
  value_serializer: Callable[[_V1 | _V2 | _V3], bytes] | None = None,
254
249
  value_deserializer: Callable[[bytes], _V1 | _V2 | _V3] | None = None,
255
- timeout: Duration | None = None,
250
+ timeout: TimeDelta | None = None,
256
251
  error: type[Exception] = TimeoutError,
257
- ttl: Duration | None = None,
252
+ ttl: TimeDelta | None = None,
258
253
  ) -> RedisHashMapKey[_K, _V1 | _V2 | _V3]: ...
259
254
  @overload
260
255
  def redis_hash_map_key(
@@ -267,9 +262,9 @@ def redis_hash_map_key(
267
262
  key_deserializer: Callable[[bytes], Any] | None = None,
268
263
  value_serializer: Callable[[_V], bytes] | None = None,
269
264
  value_deserializer: Callable[[bytes], _V] | None = None,
270
- timeout: Duration | None = None,
265
+ timeout: TimeDelta | None = None,
271
266
  error: type[Exception] = TimeoutError,
272
- ttl: Duration | None = None,
267
+ ttl: TimeDelta | None = None,
273
268
  ) -> RedisHashMapKey[_K1 | _K2, _V]: ...
274
269
  @overload
275
270
  def redis_hash_map_key(
@@ -282,9 +277,9 @@ def redis_hash_map_key(
282
277
  key_deserializer: Callable[[bytes], Any] | None = None,
283
278
  value_serializer: Callable[[_V1 | _V2], bytes] | None = None,
284
279
  value_deserializer: Callable[[bytes], _V1 | _V2] | None = None,
285
- timeout: Duration | None = None,
280
+ timeout: TimeDelta | None = None,
286
281
  error: type[Exception] = TimeoutError,
287
- ttl: Duration | None = None,
282
+ ttl: TimeDelta | None = None,
288
283
  ) -> RedisHashMapKey[_K1 | _K2, _V1 | _V2]: ...
289
284
  @overload
290
285
  def redis_hash_map_key(
@@ -297,9 +292,9 @@ def redis_hash_map_key(
297
292
  key_deserializer: Callable[[bytes], Any] | None = None,
298
293
  value_serializer: Callable[[_V1 | _V2 | _V3], bytes] | None = None,
299
294
  value_deserializer: Callable[[bytes], _V1 | _V2 | _V3] | None = None,
300
- timeout: Duration | None = None,
295
+ timeout: TimeDelta | None = None,
301
296
  error: type[Exception] = TimeoutError,
302
- ttl: Duration | None = None,
297
+ ttl: TimeDelta | None = None,
303
298
  ) -> RedisHashMapKey[_K1 | _K2, _V1 | _V2 | _V3]: ...
304
299
  @overload
305
300
  def redis_hash_map_key(
@@ -312,9 +307,9 @@ def redis_hash_map_key(
312
307
  key_deserializer: Callable[[bytes], Any] | None = None,
313
308
  value_serializer: Callable[[_V], bytes] | None = None,
314
309
  value_deserializer: Callable[[bytes], _V] | None = None,
315
- timeout: Duration | None = None,
310
+ timeout: TimeDelta | None = None,
316
311
  error: type[Exception] = TimeoutError,
317
- ttl: Duration | None = None,
312
+ ttl: TimeDelta | None = None,
318
313
  ) -> RedisHashMapKey[_K1 | _K2 | _K3, _V]: ...
319
314
  @overload
320
315
  def redis_hash_map_key(
@@ -327,9 +322,9 @@ def redis_hash_map_key(
327
322
  key_deserializer: Callable[[bytes], Any] | None = None,
328
323
  value_serializer: Callable[[_V1 | _V2], bytes] | None = None,
329
324
  value_deserializer: Callable[[bytes], _V1 | _V2] | None = None,
330
- timeout: Duration | None = None,
325
+ timeout: TimeDelta | None = None,
331
326
  error: type[Exception] = TimeoutError,
332
- ttl: Duration | None = None,
327
+ ttl: TimeDelta | None = None,
333
328
  ) -> RedisHashMapKey[_K1 | _K2 | _K3, _V1 | _V2]: ...
334
329
  @overload
335
330
  def redis_hash_map_key(
@@ -342,9 +337,9 @@ def redis_hash_map_key(
342
337
  key_deserializer: Callable[[bytes], Any] | None = None,
343
338
  value_serializer: Callable[[_V1 | _V2 | _V3], bytes] | None = None,
344
339
  value_deserializer: Callable[[bytes], _V1 | _V2 | _V3] | None = None,
345
- timeout: Duration | None = None,
340
+ timeout: TimeDelta | None = None,
346
341
  error: type[Exception] = TimeoutError,
347
- ttl: Duration | None = None,
342
+ ttl: TimeDelta | None = None,
348
343
  ) -> RedisHashMapKey[_K1 | _K2 | _K3, _V1 | _V2 | _V3]: ...
349
344
  @overload
350
345
  def redis_hash_map_key(
@@ -357,9 +352,9 @@ def redis_hash_map_key(
357
352
  key_deserializer: Callable[[bytes], Any] | None = None,
358
353
  value_serializer: Callable[[_V1 | _V2 | _V3], bytes] | None = None,
359
354
  value_deserializer: Callable[[bytes], _V1 | _V2 | _V3] | None = None,
360
- timeout: Duration | None = None,
355
+ timeout: TimeDelta | None = None,
361
356
  error: type[Exception] = TimeoutError,
362
- ttl: Duration | None = None,
357
+ ttl: TimeDelta | None = None,
363
358
  ) -> RedisHashMapKey[_K, _V]: ...
364
359
  def redis_hash_map_key(
365
360
  name: str,
@@ -371,8 +366,8 @@ def redis_hash_map_key(
371
366
  key_deserializer: Callable[[bytes], Any] | None = None,
372
367
  value_serializer: Callable[[Any], bytes] | None = None,
373
368
  value_deserializer: Callable[[bytes], Any] | None = None,
374
- timeout: Duration | None = None,
375
- ttl: Duration | None = None,
369
+ timeout: TimeDelta | None = None,
370
+ ttl: TimeDelta | None = None,
376
371
  error: type[Exception] = TimeoutError,
377
372
  ) -> RedisHashMapKey[_K, _V]:
378
373
  """Create a redis key."""
@@ -401,21 +396,21 @@ class RedisKey(Generic[_T]):
401
396
  type: TypeLike[_T]
402
397
  serializer: Callable[[_T], bytes] | None = None
403
398
  deserializer: Callable[[bytes], _T] | None = None
404
- timeout: Duration | None = None
399
+ timeout: TimeDelta | None = None
405
400
  error: MaybeType[BaseException] = TimeoutError
406
- ttl: Duration | None = None
401
+ ttl: TimeDelta | None = None
407
402
 
408
403
  async def delete(self, redis: Redis, /) -> int:
409
404
  """Delete the key from `redis`."""
410
- async with timeout_dur( # skipif-ci-and-not-linux
411
- duration=self.timeout, error=self.error
405
+ async with timeout_td( # skipif-ci-and-not-linux
406
+ self.timeout, error=self.error
412
407
  ):
413
408
  return ensure_int(await redis.delete(self.name))
414
409
 
415
410
  async def exists(self, redis: Redis, /) -> bool:
416
411
  """Check if the key exists in `redis`."""
417
- async with timeout_dur( # skipif-ci-and-not-linux
418
- duration=self.timeout, error=self.error
412
+ async with timeout_td( # skipif-ci-and-not-linux
413
+ self.timeout, error=self.error
419
414
  ):
420
415
  result = cast("Literal[0, 1]", await redis.exists(self.name))
421
416
  match result: # skipif-ci-and-not-linux
@@ -426,8 +421,8 @@ class RedisKey(Generic[_T]):
426
421
 
427
422
  async def get(self, redis: Redis, /) -> _T:
428
423
  """Get a value from `redis`."""
429
- async with timeout_dur( # skipif-ci-and-not-linux
430
- duration=self.timeout, error=self.error
424
+ async with timeout_td( # skipif-ci-and-not-linux
425
+ self.timeout, error=self.error
431
426
  ):
432
427
  result = cast("bytes | None", await redis.get(self.name))
433
428
  if result is None: # skipif-ci-and-not-linux
@@ -440,12 +435,10 @@ class RedisKey(Generic[_T]):
440
435
  """Set a value in `redis`."""
441
436
  ser = _serialize(value, serializer=self.serializer) # skipif-ci-and-not-linux
442
437
  ttl = ( # skipif-ci-and-not-linux
443
- None
444
- if self.ttl is None
445
- else round(1000 * datetime_duration_to_float(self.ttl))
438
+ None if self.ttl is None else round(self.ttl.in_milliseconds())
446
439
  )
447
- async with timeout_dur( # skipif-ci-and-not-linux
448
- duration=self.timeout, error=self.error
440
+ async with timeout_td( # skipif-ci-and-not-linux
441
+ self.timeout, error=self.error
449
442
  ):
450
443
  result = await redis.set( # skipif-ci-and-not-linux
451
444
  self.name, ser, px=ttl
@@ -461,9 +454,9 @@ def redis_key(
461
454
  *,
462
455
  serializer: Callable[[_T], bytes] | None = None,
463
456
  deserializer: Callable[[bytes], _T] | None = None,
464
- timeout: Duration | None = None,
457
+ timeout: TimeDelta | None = None,
465
458
  error: type[Exception] = TimeoutError,
466
- ttl: Duration | None = None,
459
+ ttl: TimeDelta | None = None,
467
460
  ) -> RedisKey[_T]: ...
468
461
  @overload
469
462
  def redis_key(
@@ -473,9 +466,9 @@ def redis_key(
473
466
  *,
474
467
  serializer: Callable[[_T1 | _T2], bytes] | None = None,
475
468
  deserializer: Callable[[bytes], _T1 | _T2] | None = None,
476
- timeout: Duration | None = None,
469
+ timeout: TimeDelta | None = None,
477
470
  error: type[Exception] = TimeoutError,
478
- ttl: Duration | None = None,
471
+ ttl: TimeDelta | None = None,
479
472
  ) -> RedisKey[_T1 | _T2]: ...
480
473
  @overload
481
474
  def redis_key(
@@ -485,9 +478,9 @@ def redis_key(
485
478
  *,
486
479
  serializer: Callable[[_T1 | _T2 | _T3], bytes] | None = None,
487
480
  deserializer: Callable[[bytes], _T1 | _T2 | _T3] | None = None,
488
- timeout: Duration | None = None,
481
+ timeout: TimeDelta | None = None,
489
482
  error: type[Exception] = TimeoutError,
490
- ttl: Duration | None = None,
483
+ ttl: TimeDelta | None = None,
491
484
  ) -> RedisKey[_T1 | _T2 | _T3]: ...
492
485
  @overload
493
486
  def redis_key(
@@ -497,9 +490,9 @@ def redis_key(
497
490
  *,
498
491
  serializer: Callable[[_T1 | _T2 | _T3 | _T4], bytes] | None = None,
499
492
  deserializer: Callable[[bytes], _T1 | _T2 | _T3 | _T4] | None = None,
500
- timeout: Duration | None = None,
493
+ timeout: TimeDelta | None = None,
501
494
  error: type[Exception] = TimeoutError,
502
- ttl: Duration | None = None,
495
+ ttl: TimeDelta | None = None,
503
496
  ) -> RedisKey[_T1 | _T2 | _T3 | _T4]: ...
504
497
  @overload
505
498
  def redis_key(
@@ -509,9 +502,9 @@ def redis_key(
509
502
  *,
510
503
  serializer: Callable[[_T1 | _T2 | _T3 | _T4 | _T5], bytes] | None = None,
511
504
  deserializer: Callable[[bytes], _T1 | _T2 | _T3 | _T4 | _T5] | None = None,
512
- timeout: Duration | None = None,
505
+ timeout: TimeDelta | None = None,
513
506
  error: type[Exception] = TimeoutError,
514
- ttl: Duration | None = None,
507
+ ttl: TimeDelta | None = None,
515
508
  ) -> RedisKey[_T1 | _T2 | _T3 | _T4 | _T5]: ...
516
509
  @overload
517
510
  def redis_key(
@@ -521,9 +514,9 @@ def redis_key(
521
514
  *,
522
515
  serializer: Callable[[_T1 | _T2 | _T3 | _T4 | _T5], bytes] | None = None,
523
516
  deserializer: Callable[[bytes], _T1 | _T2 | _T3 | _T4 | _T5] | None = None,
524
- timeout: Duration | None = None,
517
+ timeout: TimeDelta | None = None,
525
518
  error: type[Exception] = TimeoutError,
526
- ttl: Duration | None = None,
519
+ ttl: TimeDelta | None = None,
527
520
  ) -> RedisKey[_T]: ...
528
521
  def redis_key(
529
522
  name: str,
@@ -532,9 +525,9 @@ def redis_key(
532
525
  *,
533
526
  serializer: Callable[[Any], bytes] | None = None,
534
527
  deserializer: Callable[[bytes], Any] | None = None,
535
- timeout: Duration | None = None,
528
+ timeout: TimeDelta | None = None,
536
529
  error: type[Exception] = TimeoutError,
537
- ttl: Duration | None = None,
530
+ ttl: TimeDelta | None = None,
538
531
  ) -> RedisKey[_T]:
539
532
  """Create a redis key."""
540
533
  return RedisKey( # skipif-ci-and-not-linux
@@ -559,7 +552,7 @@ async def publish(
559
552
  /,
560
553
  *,
561
554
  serializer: Callable[[_T], EncodableT],
562
- timeout: Duration = _PUBLISH_TIMEOUT,
555
+ timeout: TimeDelta = _PUBLISH_TIMEOUT,
563
556
  ) -> ResponseT: ...
564
557
  @overload
565
558
  async def publish(
@@ -569,7 +562,7 @@ async def publish(
569
562
  /,
570
563
  *,
571
564
  serializer: None = None,
572
- timeout: Duration = _PUBLISH_TIMEOUT,
565
+ timeout: TimeDelta = _PUBLISH_TIMEOUT,
573
566
  ) -> ResponseT: ...
574
567
  @overload
575
568
  async def publish(
@@ -579,7 +572,7 @@ async def publish(
579
572
  /,
580
573
  *,
581
574
  serializer: Callable[[_T], EncodableT] | None = None,
582
- timeout: Duration = _PUBLISH_TIMEOUT,
575
+ timeout: TimeDelta = _PUBLISH_TIMEOUT,
583
576
  ) -> ResponseT: ...
584
577
  async def publish(
585
578
  redis: Redis,
@@ -588,7 +581,7 @@ async def publish(
588
581
  /,
589
582
  *,
590
583
  serializer: Callable[[_T], EncodableT] | None = None,
591
- timeout: Duration = _PUBLISH_TIMEOUT,
584
+ timeout: TimeDelta = _PUBLISH_TIMEOUT,
592
585
  ) -> ResponseT:
593
586
  """Publish an object to a channel."""
594
587
  match data, serializer: # skipif-ci-and-not-linux
@@ -600,7 +593,7 @@ async def publish(
600
593
  data_use = serializer(data)
601
594
  case _ as never:
602
595
  assert_never(never)
603
- async with timeout_dur(duration=timeout): # skipif-ci-and-not-linux
596
+ async with timeout_td(timeout): # skipif-ci-and-not-linux
604
597
  return await redis.publish(channel, data_use) # skipif-ci-and-not-linux
605
598
 
606
599
 
@@ -624,13 +617,13 @@ class PublishService(Looper[tuple[str, _T]]):
624
617
  """Service to publish items to Redis."""
625
618
 
626
619
  # base
627
- freq: Duration = field(default=MILLISECOND, repr=False)
628
- backoff: Duration = field(default=SECOND, repr=False)
620
+ freq: TimeDelta = field(default=MILLISECOND, repr=False)
621
+ backoff: TimeDelta = field(default=SECOND, repr=False)
629
622
  empty_upon_exit: bool = field(default=True, repr=False)
630
623
  # self
631
624
  redis: Redis
632
625
  serializer: Callable[[_T], EncodableT] = serialize
633
- publish_timeout: Duration = _PUBLISH_TIMEOUT
626
+ publish_timeout: TimeDelta = _PUBLISH_TIMEOUT
634
627
 
635
628
  @override
636
629
  async def core(self) -> None:
@@ -654,17 +647,17 @@ class PublishServiceMixin(Generic[_T]):
654
647
  """Mix-in for the publish service."""
655
648
 
656
649
  # base - looper
657
- publish_service_freq: Duration = field(default=MILLISECOND, repr=False)
658
- publish_service_backoff: Duration = field(default=SECOND, repr=False)
650
+ publish_service_freq: TimeDelta = field(default=MILLISECOND, repr=False)
651
+ publish_service_backoff: TimeDelta = field(default=SECOND, repr=False)
659
652
  publish_service_empty_upon_exit: bool = field(default=False, repr=False)
660
653
  publish_service_logger: str | None = field(default=None, repr=False)
661
- publish_service_timeout: Duration | None = field(default=None, repr=False)
654
+ publish_service_timeout: TimeDelta | None = field(default=None, repr=False)
662
655
  publish_service_debug: bool = field(default=False, repr=False)
663
656
  _is_pending_restart: Event = field(default_factory=Event, init=False, repr=False)
664
657
  # base - publish service
665
658
  publish_service_redis: Redis
666
659
  publish_service_serializer: Callable[[_T], EncodableT] = serialize
667
- publish_service_publish_timeout: Duration = _PUBLISH_TIMEOUT
660
+ publish_service_publish_timeout: TimeDelta = _PUBLISH_TIMEOUT
668
661
  # self
669
662
  _publish_service: PublishService[_T] = field(init=False, repr=False)
670
663
 
@@ -694,8 +687,8 @@ class PublishServiceMixin(Generic[_T]):
694
687
  ##
695
688
 
696
689
 
697
- _SUBSCRIBE_TIMEOUT: Duration = SECOND
698
- _SUBSCRIBE_SLEEP: Duration = MILLISECOND
690
+ _SUBSCRIBE_TIMEOUT: TimeDelta = SECOND
691
+ _SUBSCRIBE_SLEEP: TimeDelta = MILLISECOND
699
692
 
700
693
 
701
694
  @overload
@@ -706,8 +699,8 @@ def subscribe(
706
699
  queue: Queue[_RedisMessage],
707
700
  /,
708
701
  *,
709
- timeout: Duration | None = _SUBSCRIBE_TIMEOUT,
710
- sleep: Duration = _SUBSCRIBE_SLEEP,
702
+ timeout: TimeDelta | None = _SUBSCRIBE_TIMEOUT,
703
+ sleep: TimeDelta = _SUBSCRIBE_SLEEP,
711
704
  output: Literal["raw"],
712
705
  filter_: Callable[[_RedisMessage], bool] | None = None,
713
706
  ) -> AsyncIterator[Task[None]]: ...
@@ -719,8 +712,8 @@ def subscribe(
719
712
  queue: Queue[bytes],
720
713
  /,
721
714
  *,
722
- timeout: Duration | None = _SUBSCRIBE_TIMEOUT,
723
- sleep: Duration = _SUBSCRIBE_SLEEP,
715
+ timeout: TimeDelta | None = _SUBSCRIBE_TIMEOUT,
716
+ sleep: TimeDelta = _SUBSCRIBE_SLEEP,
724
717
  output: Literal["bytes"],
725
718
  filter_: Callable[[bytes], bool] | None = None,
726
719
  ) -> AsyncIterator[Task[None]]: ...
@@ -732,8 +725,8 @@ def subscribe(
732
725
  queue: Queue[str],
733
726
  /,
734
727
  *,
735
- timeout: Duration | None = _SUBSCRIBE_TIMEOUT,
736
- sleep: Duration = _SUBSCRIBE_SLEEP,
728
+ timeout: TimeDelta | None = _SUBSCRIBE_TIMEOUT,
729
+ sleep: TimeDelta = _SUBSCRIBE_SLEEP,
737
730
  output: Literal["text"] = "text",
738
731
  filter_: Callable[[str], bool] | None = None,
739
732
  ) -> AsyncIterator[Task[None]]: ...
@@ -745,8 +738,8 @@ def subscribe(
745
738
  queue: Queue[_T],
746
739
  /,
747
740
  *,
748
- timeout: Duration | None = _SUBSCRIBE_TIMEOUT,
749
- sleep: Duration = _SUBSCRIBE_SLEEP,
741
+ timeout: TimeDelta | None = _SUBSCRIBE_TIMEOUT,
742
+ sleep: TimeDelta = _SUBSCRIBE_SLEEP,
750
743
  output: Callable[[bytes], _T],
751
744
  filter_: Callable[[_T], bool] | None = None,
752
745
  ) -> AsyncIterator[Task[None]]: ...
@@ -757,8 +750,8 @@ async def subscribe(
757
750
  queue: Queue[_RedisMessage] | Queue[bytes] | Queue[_T],
758
751
  /,
759
752
  *,
760
- timeout: Duration | None = _SUBSCRIBE_TIMEOUT,
761
- sleep: Duration = _SUBSCRIBE_SLEEP,
753
+ timeout: TimeDelta | None = _SUBSCRIBE_TIMEOUT,
754
+ sleep: TimeDelta = _SUBSCRIBE_SLEEP,
762
755
  output: Literal["raw", "bytes", "text"] | Callable[[bytes], _T] = "text",
763
756
  filter_: Callable[[Any], bool] | None = None,
764
757
  ) -> AsyncIterator[Task[None]]:
@@ -808,14 +801,13 @@ async def _subscribe_core(
808
801
  queue: Queue[Any],
809
802
  /,
810
803
  *,
811
- timeout: Duration | None = _SUBSCRIBE_TIMEOUT,
812
- sleep: Duration = _SUBSCRIBE_SLEEP,
804
+ timeout: TimeDelta | None = _SUBSCRIBE_TIMEOUT,
805
+ sleep: TimeDelta = _SUBSCRIBE_SLEEP,
813
806
  filter_: Callable[[Any], bool] | None = None,
814
807
  ) -> None:
815
808
  timeout_use = ( # skipif-ci-and-not-linux
816
- None if timeout is None else datetime_duration_to_float(timeout)
809
+ None if timeout is None else timeout.in_seconds()
817
810
  )
818
- sleep_use = datetime_duration_to_float(sleep) # skipif-ci-and-not-linux
819
811
  is_subscribe_message = partial( # skipif-ci-and-not-linux
820
812
  _is_message, channels={c.encode() for c in channels}
821
813
  )
@@ -830,7 +822,7 @@ async def _subscribe_core(
830
822
  else:
831
823
  queue.put_nowait(transformed)
832
824
  else:
833
- await asyncio.sleep(sleep_use)
825
+ await sleep_td(sleep)
834
826
 
835
827
 
836
828
  def _is_message(
@@ -864,15 +856,15 @@ class SubscribeService(Looper[_T]):
864
856
  """Service to subscribe to Redis."""
865
857
 
866
858
  # base
867
- freq: Duration = field(default=MILLISECOND, repr=False)
868
- backoff: Duration = field(default=SECOND, repr=False)
859
+ freq: TimeDelta = field(default=MILLISECOND, repr=False)
860
+ backoff: TimeDelta = field(default=SECOND, repr=False)
869
861
  logger: str | None = field(default=__name__, repr=False)
870
862
  # self
871
863
  redis: Redis
872
864
  channel: str
873
865
  deserializer: Callable[[bytes], _T] = deserialize
874
- subscribe_timeout: Duration | None = _SUBSCRIBE_TIMEOUT
875
- subscribe_sleep: Duration = _SUBSCRIBE_SLEEP
866
+ subscribe_timeout: TimeDelta | None = _SUBSCRIBE_TIMEOUT
867
+ subscribe_sleep: TimeDelta = _SUBSCRIBE_SLEEP
876
868
  filter_: Callable[[_T], bool] | None = None
877
869
  _is_subscribed: Event = field(default_factory=Event, init=False, repr=False)
878
870
 
@@ -934,18 +926,18 @@ class SubscribeServiceMixin(Generic[_T]):
934
926
  """Mix-in for the subscribe service."""
935
927
 
936
928
  # base - looper
937
- subscribe_service_freq: Duration = field(default=MILLISECOND, repr=False)
938
- subscribe_service_backoff: Duration = field(default=SECOND, repr=False)
929
+ subscribe_service_freq: TimeDelta = field(default=MILLISECOND, repr=False)
930
+ subscribe_service_backoff: TimeDelta = field(default=SECOND, repr=False)
939
931
  subscribe_service_empty_upon_exit: bool = field(default=False, repr=False)
940
932
  subscribe_service_logger: str | None = field(default=None, repr=False)
941
- subscribe_service_timeout: Duration | None = field(default=None, repr=False)
933
+ subscribe_service_timeout: TimeDelta | None = field(default=None, repr=False)
942
934
  subscribe_service_debug: bool = field(default=False, repr=False)
943
935
  # base - looper
944
936
  subscribe_service_redis: Redis
945
937
  subscribe_service_channel: str
946
938
  subscribe_service_deserializer: Callable[[bytes], _T] = deserialize
947
- subscribe_service_subscribe_sleep: Duration = _SUBSCRIBE_SLEEP
948
- subscribe_service_subscribe_timeout: Duration | None = _SUBSCRIBE_TIMEOUT
939
+ subscribe_service_subscribe_sleep: TimeDelta = _SUBSCRIBE_SLEEP
940
+ subscribe_service_subscribe_timeout: TimeDelta | None = _SUBSCRIBE_TIMEOUT
949
941
  # self
950
942
  _subscribe_service: SubscribeService[_T] = field(init=False, repr=False)
951
943