queutils 0.8.4__py3-none-any.whl → 0.9.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.
queutils/__init__.py CHANGED
@@ -2,10 +2,15 @@ from .countable import Countable as Countable
2
2
  from .asyncqueue import AsyncQueue as AsyncQueue
3
3
  from .iterablequeue import IterableQueue as IterableQueue, QueueDone as QueueDone
4
4
  from .filequeue import FileQueue as FileQueue
5
+ from .categorycounterqueue import (
6
+ QCounter as QCounter,
7
+ CategoryCounterQueue as CategoryCounterQueue,
8
+ )
5
9
 
6
10
  __all__ = [
7
11
  "asyncqueue",
8
12
  "countable",
13
+ "categorycounterqueue",
9
14
  "filequeue",
10
15
  "iterablequeue",
11
16
  ]
queutils/asyncqueue.py CHANGED
@@ -1,7 +1,7 @@
1
1
  # -----------------------------------------------------------
2
2
  # Class AsyncQueue(asyncio.Queue, Generic[T])
3
3
  #
4
- # asyncio wrapper for non-async queue.Queue. Can be used to create
4
+ # asyncio wrapper for non-async queue.Queue. Can be used to create
5
5
  # an asyncio.Queue out of a (non-async) multiprocessing.Queue.
6
6
  #
7
7
  # -----------------------------------------------------------
@@ -10,7 +10,6 @@ __author__ = "Jylpah"
10
10
  __copyright__ = "Copyright 2024, Jylpah <Jylpah@gmail.com>"
11
11
  __credits__ = ["Jylpah"]
12
12
  __license__ = "MIT"
13
- # __version__ = "1.0"
14
13
  __maintainer__ = "Jylpah"
15
14
  __email__ = "Jylpah@gmail.com"
16
15
  __status__ = "Production"
@@ -35,18 +34,17 @@ error = logger.error
35
34
 
36
35
  class AsyncQueue(asyncio.Queue, Generic[T]):
37
36
  """
38
- Async wrapper for non-async queue.Queue. Can be used to create
37
+ Async wrapper for non-async queue.Queue. Can be used to create
39
38
  an asyncio.Queue out of a (non-async) multiprocessing.Queue.
40
39
  """
41
40
 
42
- def __init__(self, queue: Queue[T], asleep: float = 0.01):
41
+ def __init__(self, queue: Queue[T], asleep: float = 0.001):
43
42
  self._Q: Queue[T] = queue
44
43
  # self._maxsize: int = queue.maxsize
45
44
  self._done: int = 0
46
45
  self._items: int = 0
47
46
  self._sleep: float = asleep
48
47
 
49
-
50
48
  @property
51
49
  def maxsize(self) -> int:
52
50
  """not supported by queue.Queue"""
@@ -0,0 +1,116 @@
1
+ from asyncio import Queue
2
+ from typing import TypeVar
3
+ from deprecated import deprecated
4
+ from .countable import Countable
5
+ from .iterablequeue import IterableQueue, QueueDone
6
+ from collections import defaultdict
7
+ import logging
8
+
9
+ logger = logging.getLogger()
10
+ error = logger.error
11
+ message = logger.warning
12
+ verbose = logger.info
13
+ debug = logger.debug
14
+
15
+ ###########################################
16
+ #
17
+ # class CounterQueue
18
+ #
19
+ ###########################################
20
+ T = TypeVar("T")
21
+
22
+
23
+ @deprecated(version="0.9.1", reason="Use CategoryCounterQueue instead")
24
+ class CounterQueue(Queue[T], Countable):
25
+ """
26
+ CounterQueue is a asyncio.Queue for counting items
27
+ """
28
+
29
+ _counter: int
30
+ _count_items: bool
31
+ _batch: int
32
+
33
+ def __init__(
34
+ self, *args, count_items: bool = True, batch: int = 1, **kwargs
35
+ ) -> None:
36
+ super().__init__(*args, **kwargs)
37
+ self._counter = 0
38
+ self._count_items = count_items
39
+ self._batch = batch
40
+
41
+ def task_done(self) -> None:
42
+ super().task_done()
43
+ if self._count_items:
44
+ self._counter += 1
45
+ return None
46
+
47
+ @property
48
+ def count(self) -> int:
49
+ """Return number of completed tasks"""
50
+ return self._counter * self._batch
51
+
52
+ @property
53
+ def count_items(self) -> bool:
54
+ """Whether or not count items"""
55
+ return self._count_items
56
+
57
+
58
+ class CategoryCounterQueue(IterableQueue[tuple[str, int]]):
59
+ """
60
+ CategorySummerQueue is a asyncio.Queue for summing up values by category
61
+ """
62
+
63
+ _counter: defaultdict[str, int]
64
+ _batch: int
65
+
66
+ def __init__(self, *args, batch: int = 1, **kwargs) -> None:
67
+ super().__init__(*args, **kwargs)
68
+ self._batch = batch
69
+ self._counter = defaultdict(int)
70
+
71
+ async def receive(self) -> tuple[str, int]:
72
+ """Receive a category value from the queue and sum it"""
73
+ category: str
74
+ value: int
75
+ category, value = await super().get()
76
+ self._counter[category] += value
77
+ super().task_done()
78
+ return (category, value)
79
+
80
+ async def send(self, category: str = "count", value: int = 1) -> None:
81
+ """Send count of a category"""
82
+ await super().put((category, value))
83
+ return None
84
+
85
+ def get_count(self, category: str = "count") -> int:
86
+ """Return count of a category"""
87
+ return self._counter[category]
88
+
89
+ def get_counts(self) -> defaultdict[str, int]:
90
+ """Return counts of all categories"""
91
+ return self._counter
92
+
93
+ async def listen(self) -> defaultdict[str, int]:
94
+ """Listen for category values"""
95
+ try:
96
+ while True:
97
+ await self.receive()
98
+ except QueueDone:
99
+ pass
100
+ return self.get_counts()
101
+
102
+
103
+ class QCounter:
104
+ def __init__(self, Q: Queue[int]):
105
+ self._count = 0
106
+ self._Q: Queue[int] = Q
107
+
108
+ @property
109
+ def count(self) -> int:
110
+ return self._count
111
+
112
+ async def start(self) -> None:
113
+ """Read and count items from Q"""
114
+ while True:
115
+ self._count += await self._Q.get()
116
+ self._Q.task_done()
queutils/iterablequeue.py CHANGED
@@ -1,7 +1,7 @@
1
1
  # -----------------------------------------------------------
2
2
  # Class IterableQueue(asyncio.Queue[T], AsyncIterable[T], Countable)
3
3
  #
4
- # IterableQueue is asyncio.Queue subclass that can be iterated asynchronusly.
4
+ # IterableQueue is asyncio.Queue subclass that can be iterated asynchronusly.
5
5
  # IterableQueue terminates automatically when the queue has been
6
6
  # filled and emptied.
7
7
  #
@@ -23,7 +23,7 @@ from .countable import Countable
23
23
  import logging
24
24
 
25
25
  # Setup logging
26
- logger = logging.getLogger()
26
+ logger = logging.getLogger(__name__)
27
27
  error = logger.error
28
28
  message = logger.warning
29
29
  verbose = logger.info
@@ -31,24 +31,26 @@ debug = logger.debug
31
31
 
32
32
  T = TypeVar("T")
33
33
 
34
+
34
35
  class QueueDone(Exception):
35
36
  """
36
37
  Exception to mark an IterableQueue as filled and emptied i.e. done
37
38
  """
39
+
38
40
  pass
39
41
 
40
42
 
41
43
  class IterableQueue(Queue[T], AsyncIterable[T], Countable):
42
44
  """
43
- IterableQueue is asyncio.Queue subclass that can be iterated asynchronusly.
44
-
45
+ IterableQueue is asyncio.Queue subclass that can be iterated asynchronusly.
46
+
45
47
  IterableQueue terminates automatically when the queue has been
46
48
  filled and emptied. Supports:
47
49
  - asyncio.Queue() interface, _nowait() methods are experimental
48
50
  - AsyncIterable(): async for item in queue:
49
51
  - Automatic termination of the consumers when the queue has been emptied with QueueDone exception
50
52
  - Producers must be registered with add_producer() and they must notify the queue
51
- with finish() once they have finished adding items
53
+ with finish() once they have finished adding items
52
54
  - Countable interface to count number of items task_done() through 'count' property
53
55
  - Countable property can be disabled with count_items=False. This is useful when you
54
56
  want to sum the count of multiple IterableQueues
@@ -74,16 +76,16 @@ class IterableQueue(Queue[T], AsyncIterable[T], Countable):
74
76
 
75
77
  @property
76
78
  def is_filled(self) -> bool:
77
- """"
78
- True if all the producers finished filling the queue.
79
+ """ "
80
+ True if all the producers finished filling the queue.
79
81
  New items cannot be added to a filled queue nor can new producers can be added.
80
82
  """
81
83
  return self._filled.is_set()
82
-
84
+
83
85
  @property
84
86
  def is_done(self) -> bool:
85
87
  """
86
- Has the queue been filled, emptied and all the items have been marked with task_done()
88
+ Has the queue been filled, emptied and all the items have been marked with task_done()
87
89
  """
88
90
  return self.is_filled and self.empty() and not self.has_wip
89
91
 
@@ -91,7 +93,6 @@ class IterableQueue(Queue[T], AsyncIterable[T], Countable):
91
93
  def maxsize(self) -> int:
92
94
  return self._Q.maxsize
93
95
 
94
-
95
96
  def full(self) -> bool:
96
97
  """
97
98
  True if the queue is full
@@ -122,8 +123,8 @@ class IterableQueue(Queue[T], AsyncIterable[T], Countable):
122
123
  @property
123
124
  def wip(self) -> int:
124
125
  """
125
- Number of items in progress i.e. items that have been
126
- read from the queue, but not marked with task_done()
126
+ Number of items in progress i.e. items that have been
127
+ read from the queue, but not marked with task_done()
127
128
  """
128
129
  return self._wip
129
130
 
@@ -236,7 +237,7 @@ class IterableQueue(Queue[T], AsyncIterable[T], Countable):
236
237
  def get_nowait(self) -> T:
237
238
  """
238
239
  Experimental asyncio.Queue.get_nowait() implementation
239
- """
240
+ """
240
241
  item: T | None = self._Q.get_nowait()
241
242
  if item is None:
242
243
  self._empty.set()
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: queutils
3
- Version: 0.8.4
3
+ Version: 0.9.1
4
4
  Summary: Handy Python Queue utilies
5
5
  Project-URL: Homepage, https://github.com/Jylpah/queutils
6
6
  Project-URL: Bug Tracker, https://github.com/Jylpah/queutils/issues
@@ -14,6 +14,7 @@ Classifier: Programming Language :: Python :: 3
14
14
  Classifier: Topic :: Software Development :: Libraries
15
15
  Requires-Python: >=3.11
16
16
  Requires-Dist: aioconsole>=0.6
17
+ Requires-Dist: deprecated>=1.2.18
17
18
  Provides-Extra: dev
18
19
  Requires-Dist: build>=0.10; extra == 'dev'
19
20
  Requires-Dist: hatchling>=1.22.4; extra == 'dev'
@@ -25,6 +26,7 @@ Requires-Dist: pytest-datafiles>=3.0; extra == 'dev'
25
26
  Requires-Dist: pytest-timeout>=2.2; extra == 'dev'
26
27
  Requires-Dist: pytest>=8.0; extra == 'dev'
27
28
  Requires-Dist: ruff>=0.1.9; extra == 'dev'
29
+ Requires-Dist: types-deprecated>=1.2.15; extra == 'dev'
28
30
  Description-Content-Type: text/markdown
29
31
 
30
32
  [![Python package](https://github.com/Jylpah/queutils/actions/workflows/python-package.yml/badge.svg)](https://github.com/Jylpah/queutils/actions/workflows/python-package.yml) [![codecov](https://codecov.io/gh/Jylpah/queutils/graph/badge.svg?token=rMKdbfHOFs)](https://codecov.io/gh/Jylpah/queutils)
@@ -0,0 +1,11 @@
1
+ queutils/__init__.py,sha256=buANyRlxO1x4G_EBE3tYFpPtZGSepJDKRkWl-zKct1M,453
2
+ queutils/asyncqueue.py,sha256=GZRmlWTBQoKzTf7xr4MI-qhNqvIiaNWswAxFokP91Lg,2789
3
+ queutils/categorycounterqueue.py,sha256=Ku5pAJXSsoNyUsuWkQe9w7SaPeiPwPHFMdZFqA0LtBw,3097
4
+ queutils/countable.py,sha256=YSi7ILf9CuB5Tm3T4UUMEFlveqzqcmomfqJAlLGHEz8,172
5
+ queutils/filequeue.py,sha256=q2ly9H-lSCq6xuOqT1IlWgyCVyLoZiKbc0NuzmkF4aw,5360
6
+ queutils/iterablequeue.py,sha256=ZXwa9040yTawL1DMMNBXgQKiYr32nmzuSbgi-raAtZc,8664
7
+ queutils/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ queutils-0.9.1.dist-info/METADATA,sha256=zT3br-kHUXjDGp2QhPxW_K-EvP212VUYWZNbjTb-MUA,4281
9
+ queutils-0.9.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
10
+ queutils-0.9.1.dist-info/licenses/LICENSE,sha256=J1zeIKU2JVQmhwO2hHQDK8WR6zjVZ-wX8r7ZlL45AbI,1063
11
+ queutils-0.9.1.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.22.4
2
+ Generator: hatchling 1.27.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,10 +0,0 @@
1
- queutils/__init__.py,sha256=MboAom80iQTQURz0liGv_f2ae2Np8YA5ORX1LwsNa50,311
2
- queutils/asyncqueue.py,sha256=cZPrXJgRCK0iOtE6k-VTzA9kcDDg818h9v0cwYzm2g0,2813
3
- queutils/countable.py,sha256=YSi7ILf9CuB5Tm3T4UUMEFlveqzqcmomfqJAlLGHEz8,172
4
- queutils/filequeue.py,sha256=q2ly9H-lSCq6xuOqT1IlWgyCVyLoZiKbc0NuzmkF4aw,5360
5
- queutils/iterablequeue.py,sha256=hygOtgRRuqaPebcK27Ixm_KOOW0MnlKmBNcYreQoWOA,8677
6
- queutils/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
- queutils-0.8.4.dist-info/METADATA,sha256=kIu1OwdfGdiStIcU4DjLjkCfbvtEHMxBirj16Ba98gc,4191
8
- queutils-0.8.4.dist-info/WHEEL,sha256=uNdcs2TADwSd5pVaP0Z_kcjcvvTUklh2S7bxZMF8Uj0,87
9
- queutils-0.8.4.dist-info/licenses/LICENSE,sha256=J1zeIKU2JVQmhwO2hHQDK8WR6zjVZ-wX8r7ZlL45AbI,1063
10
- queutils-0.8.4.dist-info/RECORD,,