localqueue 0.3.0__py3-none-any.whl → 0.3.2__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.
localqueue/__init__.py CHANGED
@@ -16,6 +16,7 @@ from .retry import (
16
16
  PersistentRetrying,
17
17
  RetryRecord,
18
18
  SQLiteAttemptStore,
19
+ close_default_store,
19
20
  configure_default_store,
20
21
  configure_default_store_factory,
21
22
  idempotency_key_from_id,
@@ -55,6 +56,7 @@ __all__ = [
55
56
  "SQLiteAttemptStore",
56
57
  "SQLiteQueueStore",
57
58
  "__version__",
59
+ "close_default_store",
58
60
  "configure_default_store",
59
61
  "configure_default_store_factory",
60
62
  "idempotency_key_from_id",
localqueue/cli.py CHANGED
@@ -8,17 +8,16 @@ import subprocess
8
8
  import sys
9
9
  import time
10
10
  from collections import Counter
11
- from collections.abc import Callable
12
11
  from contextlib import contextmanager
13
12
  from dataclasses import dataclass
14
13
  from pathlib import Path
15
14
  from queue import Empty
16
- from types import FrameType
17
- from typing import Any, Iterator
15
+ from typing import Any, Iterator, TYPE_CHECKING
18
16
 
19
17
  from tenacity import wait_none
20
18
 
21
19
  from .failure import is_permanent_failure
20
+ from .paths import default_queue_store_path, default_retry_store_path
22
21
  from .queue import PersistentQueue
23
22
  from .retry import (
24
23
  PersistentRetryExhausted,
@@ -34,8 +33,12 @@ from .worker import (
34
33
  _sleep_for_policy,
35
34
  )
36
35
 
37
- DEFAULT_STORE_PATH = "localqueue_queue.sqlite3"
38
- DEFAULT_RETRY_STORE_PATH = "localqueue_retries.sqlite3"
36
+ if TYPE_CHECKING:
37
+ from types import FrameType
38
+ from collections.abc import Callable
39
+
40
+ DEFAULT_STORE_PATH = str(default_queue_store_path())
41
+ DEFAULT_RETRY_STORE_PATH = str(default_retry_store_path())
39
42
  CONFIG_FILENAME = "config.yaml"
40
43
 
41
44
 
@@ -113,7 +116,20 @@ def _build_app(typer: Any, yaml: Any, console: Any, err_console: Any) -> Any:
113
116
  app.add_typer(queue_app, name="queue")
114
117
  app.add_typer(retry_app, name="retry")
115
118
  app.add_typer(config_app, name="config")
119
+ _register_config_commands(config_app, typer, yaml, console, err_console, config)
120
+ _register_queue_commands(queue_app, typer, console, err_console, config)
121
+ _register_retry_commands(retry_app, typer, console, err_console, config)
122
+ return app
116
123
 
124
+
125
+ def _register_config_commands(
126
+ config_app: Any,
127
+ typer: Any,
128
+ yaml: Any,
129
+ console: Any,
130
+ err_console: Any,
131
+ config: dict[str, Any],
132
+ ) -> None:
117
133
  @config_app.command("path")
118
134
  def config_path() -> None:
119
135
  console.print(str(_config_path()))
@@ -124,7 +140,7 @@ def _build_app(typer: Any, yaml: Any, console: Any, err_console: Any) -> Any:
124
140
 
125
141
  @config_app.command("init")
126
142
  def config_init(
127
- store_path: str = typer.Option(DEFAULT_STORE_PATH, "--store-path"),
143
+ store_path: str | None = typer.Option(None, "--store-path"),
128
144
  retry_store_path: str | None = typer.Option(None, "--retry-store-path"),
129
145
  dead_letter_ttl_seconds: float | None = typer.Option(
130
146
  None, "--dead-letter-ttl-seconds", min=0.0
@@ -141,7 +157,7 @@ def _build_app(typer: Any, yaml: Any, console: Any, err_console: Any) -> Any:
141
157
  )
142
158
  raise typer.Exit(1)
143
159
 
144
- new_config: dict[str, Any] = {"store_path": store_path}
160
+ new_config: dict[str, Any] = {"store_path": _resolve_store_path(store_path, {})}
145
161
  if retry_store_path is not None:
146
162
  new_config["retry_store_path"] = retry_store_path
147
163
  if dead_letter_ttl_seconds is not None:
@@ -180,6 +196,26 @@ def _build_app(typer: Any, yaml: Any, console: Any, err_console: Any) -> Any:
180
196
  config.update(updated)
181
197
  _print_json(console, config)
182
198
 
199
+
200
+ def _register_queue_commands(
201
+ queue_app: Any,
202
+ typer: Any,
203
+ console: Any,
204
+ err_console: Any,
205
+ config: dict[str, Any],
206
+ ) -> None:
207
+ _register_queue_basic_commands(queue_app, typer, console, err_console, config)
208
+ _register_queue_admin_commands(queue_app, typer, console, err_console, config)
209
+ _register_queue_worker_commands(queue_app, typer, console, err_console, config)
210
+
211
+
212
+ def _register_queue_basic_commands(
213
+ queue_app: Any,
214
+ typer: Any,
215
+ console: Any,
216
+ err_console: Any,
217
+ config: dict[str, Any],
218
+ ) -> None:
183
219
  @queue_app.command("add")
184
220
  def queue_add(
185
221
  queue: str,
@@ -209,6 +245,17 @@ def _build_app(typer: Any, yaml: Any, console: Any, err_console: Any) -> Any:
209
245
  )
210
246
  _print_json(console, _message_payload(message))
211
247
 
248
+ _register_queue_message_commands(queue_app, typer, console, err_console, config)
249
+ _register_queue_maintenance_commands(queue_app, typer, console, err_console, config)
250
+
251
+
252
+ def _register_queue_message_commands(
253
+ queue_app: Any,
254
+ typer: Any,
255
+ console: Any,
256
+ err_console: Any,
257
+ config: dict[str, Any],
258
+ ) -> None:
212
259
  @queue_app.command("pop")
213
260
  def queue_pop(
214
261
  queue: str,
@@ -318,6 +365,27 @@ def _build_app(typer: Any, yaml: Any, console: Any, err_console: Any) -> Any:
318
365
  ) -> None:
319
366
  console.print(_queue(queue, _resolve_store_path(store_path, config)).qsize())
320
367
 
368
+
369
+ def _register_queue_maintenance_commands(
370
+ queue_app: Any,
371
+ typer: Any,
372
+ console: Any,
373
+ err_console: Any,
374
+ config: dict[str, Any],
375
+ ) -> None:
376
+ _register_queue_stats_commands(queue_app, typer, console, err_console, config)
377
+ _register_queue_dead_commands(queue_app, typer, console, err_console, config)
378
+ _register_queue_requeue_commands(queue_app, typer, console, err_console, config)
379
+ _register_queue_purge_commands(queue_app, typer, console, err_console, config)
380
+
381
+
382
+ def _register_queue_stats_commands(
383
+ queue_app: Any,
384
+ typer: Any,
385
+ console: Any,
386
+ err_console: Any,
387
+ config: dict[str, Any],
388
+ ) -> None:
321
389
  @queue_app.command("stats")
322
390
  def queue_stats(
323
391
  queue: str,
@@ -361,6 +429,14 @@ def _build_app(typer: Any, yaml: Any, console: Any, err_console: Any) -> Any:
361
429
  },
362
430
  )
363
431
 
432
+
433
+ def _register_queue_dead_commands(
434
+ queue_app: Any,
435
+ typer: Any,
436
+ console: Any,
437
+ err_console: Any,
438
+ config: dict[str, Any],
439
+ ) -> None:
364
440
  @queue_app.command("dead")
365
441
  def queue_dead(
366
442
  queue: str,
@@ -433,39 +509,14 @@ def _build_app(typer: Any, yaml: Any, console: Any, err_console: Any) -> Any:
433
509
  failed_within=failed_within,
434
510
  )
435
511
 
436
- @retry_app.command("prune")
437
- def retry_prune(
438
- older_than: float | None = typer.Option(None, "--older-than", min=0.0),
439
- retry_store_path: str | None = typer.Option(None, "--retry-store-path"),
440
- dry_run: bool = typer.Option(False, "--dry-run"),
441
- ) -> None:
442
- store = SQLiteAttemptStore(_resolve_retry_store_path(retry_store_path, config))
443
- try:
444
- resolved_older_than = _resolve_retry_record_ttl(older_than, config)
445
- if resolved_older_than is None:
446
- err_console.print(
447
- "[red]pass --older-than or configure retry_record_ttl_seconds[/red]"
448
- )
449
- raise typer.Exit(1)
450
- now = time.time()
451
- deleted = (
452
- store.count_exhausted_older_than(
453
- older_than=resolved_older_than, now=now
454
- )
455
- if dry_run
456
- else store.prune_exhausted(older_than=resolved_older_than, now=now)
457
- )
458
- finally:
459
- store.close()
460
- _print_json(
461
- console,
462
- {
463
- "dry_run": dry_run,
464
- "older_than": resolved_older_than,
465
- "would_delete" if dry_run else "deleted": deleted,
466
- },
467
- )
468
512
 
513
+ def _register_queue_requeue_commands(
514
+ queue_app: Any,
515
+ typer: Any,
516
+ console: Any,
517
+ err_console: Any,
518
+ config: dict[str, Any],
519
+ ) -> None:
469
520
  @queue_app.command("requeue-dead")
470
521
  def queue_requeue_dead(
471
522
  queue: str,
@@ -517,6 +568,14 @@ def _build_app(typer: Any, yaml: Any, console: Any, err_console: Any) -> Any:
517
568
  )
518
569
  _print_json(console, {"id": message_id, "state": "requeued"})
519
570
 
571
+
572
+ def _register_queue_purge_commands(
573
+ queue_app: Any,
574
+ typer: Any,
575
+ console: Any,
576
+ err_console: Any,
577
+ config: dict[str, Any],
578
+ ) -> None:
520
579
  @queue_app.command("purge")
521
580
  def queue_purge(
522
581
  queue: str,
@@ -528,6 +587,55 @@ def _build_app(typer: Any, yaml: Any, console: Any, err_console: Any) -> Any:
528
587
  _emit_event(err_console, "queue.purge", queue=queue, deleted=deleted)
529
588
  console.print(deleted)
530
589
 
590
+
591
+ def _register_retry_commands(
592
+ retry_app: Any,
593
+ typer: Any,
594
+ console: Any,
595
+ err_console: Any,
596
+ config: dict[str, Any],
597
+ ) -> None:
598
+ @retry_app.command("prune")
599
+ def retry_prune(
600
+ older_than: float | None = typer.Option(None, "--older-than", min=0.0),
601
+ retry_store_path: str | None = typer.Option(None, "--retry-store-path"),
602
+ dry_run: bool = typer.Option(False, "--dry-run"),
603
+ ) -> None:
604
+ store = SQLiteAttemptStore(_resolve_retry_store_path(retry_store_path, config))
605
+ try:
606
+ resolved_older_than = _resolve_retry_record_ttl(older_than, config)
607
+ if resolved_older_than is None:
608
+ err_console.print(
609
+ "[red]pass --older-than or configure retry_record_ttl_seconds[/red]"
610
+ )
611
+ raise typer.Exit(1)
612
+ now = time.time()
613
+ deleted = (
614
+ store.count_exhausted_older_than(
615
+ older_than=resolved_older_than, now=now
616
+ )
617
+ if dry_run
618
+ else store.prune_exhausted(older_than=resolved_older_than, now=now)
619
+ )
620
+ finally:
621
+ store.close()
622
+ _print_json(
623
+ console,
624
+ {
625
+ "dry_run": dry_run,
626
+ "older_than": resolved_older_than,
627
+ "would_delete" if dry_run else "deleted": deleted,
628
+ },
629
+ )
630
+
631
+
632
+ def _register_queue_admin_commands(
633
+ queue_app: Any,
634
+ typer: Any,
635
+ console: Any,
636
+ err_console: Any,
637
+ config: dict[str, Any],
638
+ ) -> None:
531
639
  @queue_app.command("process")
532
640
  def queue_process(
533
641
  queue: str,
@@ -605,6 +713,14 @@ def _build_app(typer: Any, yaml: Any, console: Any, err_console: Any) -> Any:
605
713
  if exit_code:
606
714
  raise typer.Exit(exit_code)
607
715
 
716
+
717
+ def _register_queue_worker_commands(
718
+ queue_app: Any,
719
+ typer: Any,
720
+ console: Any,
721
+ err_console: Any,
722
+ config: dict[str, Any],
723
+ ) -> None:
608
724
  @queue_app.command("exec")
609
725
  def queue_exec(
610
726
  queue: str,
@@ -680,8 +796,6 @@ def _build_app(typer: Any, yaml: Any, console: Any, err_console: Any) -> Any:
680
796
  if exit_code:
681
797
  raise typer.Exit(exit_code)
682
798
 
683
- return app
684
-
685
799
 
686
800
  def _queue(
687
801
  name: str, store_path: str, *, lease_timeout: float = 30.0
@@ -859,91 +973,200 @@ def _process_queue_messages(
859
973
  resolved_policy = (
860
974
  worker_policy if worker_policy is not None else PersistentWorkerConfig()
861
975
  )
976
+ owned_retry_store: SQLiteAttemptStore | None = None
862
977
 
863
- while forever or processed < max_jobs:
864
- if shutdown.requested:
865
- if forever:
866
- _print_json(console, {"state": "stopped", "processed": processed})
867
- return 0
868
-
869
- if worker_id is not None:
870
- queue.record_worker_heartbeat(worker_id)
871
- _sleep_for_policy(policy_state, resolved_policy)
978
+ try:
979
+ while forever or processed < max_jobs:
980
+ if shutdown.requested:
981
+ if forever:
982
+ _print_json(console, {"state": "stopped", "processed": processed})
983
+ return 0
872
984
 
873
- try:
874
- message = queue.get_message(
985
+ iteration, owned_retry_store, empty_queue = _process_queue_iteration(
986
+ queue,
987
+ handler,
988
+ console=console,
989
+ err_console=err_console,
990
+ policy_state=policy_state,
991
+ resolved_policy=resolved_policy,
992
+ retry_store_path=retry_store_path,
993
+ owned_retry_store=owned_retry_store,
994
+ max_tries=max_tries,
995
+ worker_id=worker_id,
875
996
  block=block,
876
- timeout=_poll_timeout(forever, block, timeout),
877
- leased_by=worker_id,
997
+ timeout=timeout,
998
+ idle_sleep=idle_sleep,
999
+ release_delay=release_delay,
1000
+ dead_letter_on_exhaustion=dead_letter_on_exhaustion,
1001
+ log_events=log_events,
1002
+ mode=mode,
1003
+ forever=forever,
878
1004
  )
879
- except Empty:
880
- if forever:
881
- if not block:
882
- time.sleep(idle_sleep)
883
- continue
884
- if processed == 0:
885
- if err_console is not None:
1005
+ if empty_queue:
1006
+ if processed == 0 and err_console is not None:
886
1007
  err_console.print("[yellow]queue is empty[/yellow]")
887
- return 1
888
- break
1008
+ if processed == 0:
1009
+ return 1
1010
+ break
1011
+ assert iteration is not None
1012
+ if _handle_processed_queue_result(
1013
+ queue,
1014
+ iteration.message,
1015
+ iteration.process_result,
1016
+ console=console,
1017
+ worker_id=worker_id,
1018
+ policy_state=policy_state,
1019
+ ):
1020
+ processed += 1
1021
+ continue
1022
+ if _handle_failed_queue_result(
1023
+ queue,
1024
+ iteration.message,
1025
+ iteration.process_result,
1026
+ console=console,
1027
+ worker_id=worker_id,
1028
+ policy_state=policy_state,
1029
+ resolved_policy=resolved_policy,
1030
+ forever=forever,
1031
+ ):
1032
+ continue
1033
+ return 1
889
1034
 
890
- if log_events and err_console is not None:
891
- _emit_event(
892
- err_console,
893
- f"{mode}.lease",
894
- queue=message.queue,
895
- message_id=message.id,
896
- leased_by=message.leased_by,
897
- attempts=message.attempts,
898
- leased_until=message.leased_until,
899
- )
1035
+ return 0
1036
+ finally:
1037
+ if owned_retry_store is not None:
1038
+ owned_retry_store.close()
900
1039
 
901
- result = _process_message(
902
- queue,
903
- message,
904
- handler,
905
- retry_store_path=retry_store_path,
906
- max_tries=max_tries,
907
- release_delay=release_delay,
908
- dead_letter_on_exhaustion=dead_letter_on_exhaustion,
909
- log_events=log_events,
910
- mode=mode,
911
- err_console=err_console,
912
- )
913
- if result.processed:
914
- processed += 1
915
- _record_success(policy_state)
916
- if worker_id is not None:
917
- queue.record_worker_heartbeat(worker_id)
918
- _print_json(console, {"id": message.id, "state": "acked"})
919
- continue
920
1040
 
921
- _record_failure(
922
- policy_state,
923
- resolved_policy,
924
- permanent=result.permanent_failure,
925
- )
1041
+ @dataclass(slots=True)
1042
+ class _QueueIterationResult:
1043
+ message: QueueMessage
1044
+ process_result: _ProcessResult
926
1045
 
927
- payload = (
928
- _message_payload(current_message)
929
- if (current_message := queue.inspect(message.id)) is not None
930
- else {"id": message.id, "queue": message.queue}
931
- )
932
- _print_json(
933
- console,
934
- {
935
- **payload,
936
- "state": "failed",
937
- "last_error": result.last_error,
938
- },
1046
+
1047
+ def _process_queue_iteration(
1048
+ queue: PersistentQueue,
1049
+ handler: Callable[[Any], Any],
1050
+ *,
1051
+ console: Any,
1052
+ err_console: Any,
1053
+ policy_state: WorkerPolicyState,
1054
+ resolved_policy: PersistentWorkerConfig,
1055
+ retry_store_path: str | None,
1056
+ owned_retry_store: SQLiteAttemptStore | None,
1057
+ max_tries: int,
1058
+ worker_id: str | None,
1059
+ block: bool,
1060
+ timeout: float | None,
1061
+ idle_sleep: float,
1062
+ release_delay: float,
1063
+ dead_letter_on_exhaustion: bool,
1064
+ log_events: bool,
1065
+ mode: str,
1066
+ forever: bool,
1067
+ ) -> tuple[_QueueIterationResult | None, SQLiteAttemptStore | None, bool]:
1068
+ if worker_id is not None:
1069
+ queue.record_worker_heartbeat(worker_id)
1070
+ _sleep_for_policy(policy_state, resolved_policy)
1071
+
1072
+ try:
1073
+ message = queue.get_message(
1074
+ block=block,
1075
+ timeout=_poll_timeout(forever, block, timeout),
1076
+ leased_by=worker_id,
939
1077
  )
940
- if worker_id is not None:
941
- queue.record_worker_heartbeat(worker_id)
1078
+ except Empty:
942
1079
  if forever:
943
- continue
944
- return 1
1080
+ if not block:
1081
+ time.sleep(idle_sleep)
1082
+ return None, owned_retry_store, True
1083
+ return None, owned_retry_store, True
1084
+
1085
+ if log_events and err_console is not None:
1086
+ _emit_event(
1087
+ err_console,
1088
+ f"{mode}.lease",
1089
+ queue=message.queue,
1090
+ message_id=message.id,
1091
+ leased_by=message.leased_by,
1092
+ attempts=message.attempts,
1093
+ leased_until=message.leased_until,
1094
+ )
1095
+
1096
+ if retry_store_path is not None and owned_retry_store is None:
1097
+ owned_retry_store = SQLiteAttemptStore(retry_store_path)
1098
+
1099
+ result = _process_message(
1100
+ queue,
1101
+ message,
1102
+ handler,
1103
+ retry_store=owned_retry_store,
1104
+ retry_store_path=None if owned_retry_store is not None else retry_store_path,
1105
+ max_tries=max_tries,
1106
+ release_delay=release_delay,
1107
+ dead_letter_on_exhaustion=dead_letter_on_exhaustion,
1108
+ log_events=log_events,
1109
+ mode=mode,
1110
+ err_console=err_console,
1111
+ )
1112
+ return (
1113
+ _QueueIterationResult(message=message, process_result=result),
1114
+ owned_retry_store,
1115
+ False,
1116
+ )
945
1117
 
946
- return 0
1118
+
1119
+ def _handle_processed_queue_result(
1120
+ queue: PersistentQueue,
1121
+ message: QueueMessage,
1122
+ result: _ProcessResult,
1123
+ *,
1124
+ console: Any,
1125
+ worker_id: str | None,
1126
+ policy_state: WorkerPolicyState,
1127
+ ) -> bool:
1128
+ if not result.processed:
1129
+ return False
1130
+ _record_success(policy_state)
1131
+ if worker_id is not None:
1132
+ queue.record_worker_heartbeat(worker_id)
1133
+ _print_json(console, {"id": message.id, "state": "acked"})
1134
+ return True
1135
+
1136
+
1137
+ def _handle_failed_queue_result(
1138
+ queue: PersistentQueue,
1139
+ message: QueueMessage,
1140
+ result: _ProcessResult,
1141
+ *,
1142
+ console: Any,
1143
+ worker_id: str | None,
1144
+ policy_state: WorkerPolicyState,
1145
+ resolved_policy: PersistentWorkerConfig,
1146
+ forever: bool,
1147
+ ) -> bool:
1148
+ _record_failure(
1149
+ policy_state,
1150
+ resolved_policy,
1151
+ permanent=result.permanent_failure,
1152
+ )
1153
+
1154
+ payload = (
1155
+ _message_payload(current_message)
1156
+ if (current_message := queue.inspect(message.id)) is not None
1157
+ else {"id": message.id, "queue": message.queue}
1158
+ )
1159
+ _print_json(
1160
+ console,
1161
+ {
1162
+ **payload,
1163
+ "state": "failed",
1164
+ "last_error": result.last_error,
1165
+ },
1166
+ )
1167
+ if worker_id is not None:
1168
+ queue.record_worker_heartbeat(worker_id)
1169
+ return forever
947
1170
 
948
1171
 
949
1172
  def _print_dead_letters(
@@ -1122,13 +1345,13 @@ def _write_config(yaml: Any, config: dict[str, Any], path: Path | None = None) -
1122
1345
 
1123
1346
 
1124
1347
  def _resolve_store_path(explicit: str | None, config: dict[str, Any]) -> str:
1125
- return str(explicit or config.get("store_path") or DEFAULT_STORE_PATH)
1348
+ return str(explicit or config.get("store_path") or default_queue_store_path())
1126
1349
 
1127
1350
 
1128
1351
  def _resolve_retry_store_path(explicit: str | None, config: dict[str, Any]) -> str:
1129
1352
  value = explicit if explicit is not None else config.get("retry_store_path")
1130
1353
  if value is None:
1131
- return DEFAULT_RETRY_STORE_PATH
1354
+ return str(default_retry_store_path())
1132
1355
  return str(value)
1133
1356
 
1134
1357
 
localqueue/failure.py CHANGED
@@ -1,27 +1,19 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import Any
3
+ from typing import Protocol
4
4
 
5
5
  _PERMANENT_FAILURE_TYPES = (
6
- AssertionError,
7
- ArithmeticError,
8
- AttributeError,
9
- FileNotFoundError,
10
6
  ImportError,
11
- IndexError,
12
- IsADirectoryError,
13
- KeyError,
14
- LookupError,
15
7
  ModuleNotFoundError,
16
8
  NameError,
17
- NotADirectoryError,
18
- TypeError,
19
- UnicodeError,
20
- ValueError,
21
9
  )
22
10
 
23
11
 
24
- def is_permanent_failure(error: BaseException | Any) -> bool:
12
+ class _ExitCodeCarrier(Protocol):
13
+ exit_code: int
14
+
15
+
16
+ def is_permanent_failure(error: BaseException | _ExitCodeCarrier) -> bool:
25
17
  if getattr(error, "exit_code", None) == 127:
26
18
  return True
27
19
  return isinstance(error, _PERMANENT_FAILURE_TYPES)
localqueue/paths.py ADDED
@@ -0,0 +1,23 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ from pathlib import Path
5
+
6
+ APP_DIR_NAME = "localqueue"
7
+ DEFAULT_QUEUE_DB_NAME = "queue.sqlite3"
8
+ DEFAULT_RETRY_DB_NAME = "retries.sqlite3"
9
+
10
+
11
+ def data_dir() -> Path:
12
+ data_home = os.environ.get("XDG_DATA_HOME")
13
+ if data_home:
14
+ return Path(data_home) / APP_DIR_NAME
15
+ return Path.home() / ".local" / "share" / APP_DIR_NAME
16
+
17
+
18
+ def default_queue_store_path() -> Path:
19
+ return data_dir() / DEFAULT_QUEUE_DB_NAME
20
+
21
+
22
+ def default_retry_store_path() -> Path:
23
+ return data_dir() / DEFAULT_RETRY_DB_NAME