ez-a-sync 0.22.14__py3-none-any.whl → 0.22.16__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.

Potentially problematic release.


This version of ez-a-sync might be problematic. Click here for more details.

Files changed (73) hide show
  1. a_sync/ENVIRONMENT_VARIABLES.py +37 -5
  2. a_sync/__init__.py +53 -12
  3. a_sync/_smart.py +231 -28
  4. a_sync/_typing.py +112 -15
  5. a_sync/a_sync/__init__.py +35 -10
  6. a_sync/a_sync/_descriptor.py +248 -38
  7. a_sync/a_sync/_flags.py +78 -9
  8. a_sync/a_sync/_helpers.py +46 -13
  9. a_sync/a_sync/_kwargs.py +33 -8
  10. a_sync/a_sync/_meta.py +149 -28
  11. a_sync/a_sync/abstract.py +150 -28
  12. a_sync/a_sync/base.py +34 -16
  13. a_sync/a_sync/config.py +85 -14
  14. a_sync/a_sync/decorator.py +441 -139
  15. a_sync/a_sync/function.py +709 -147
  16. a_sync/a_sync/method.py +437 -110
  17. a_sync/a_sync/modifiers/__init__.py +85 -5
  18. a_sync/a_sync/modifiers/cache/__init__.py +116 -17
  19. a_sync/a_sync/modifiers/cache/memory.py +130 -20
  20. a_sync/a_sync/modifiers/limiter.py +101 -22
  21. a_sync/a_sync/modifiers/manager.py +142 -16
  22. a_sync/a_sync/modifiers/semaphores.py +121 -15
  23. a_sync/a_sync/property.py +383 -82
  24. a_sync/a_sync/singleton.py +44 -19
  25. a_sync/aliases.py +0 -1
  26. a_sync/asyncio/__init__.py +140 -1
  27. a_sync/asyncio/as_completed.py +213 -79
  28. a_sync/asyncio/create_task.py +70 -20
  29. a_sync/asyncio/gather.py +125 -58
  30. a_sync/asyncio/utils.py +3 -3
  31. a_sync/exceptions.py +248 -26
  32. a_sync/executor.py +164 -69
  33. a_sync/future.py +1227 -168
  34. a_sync/iter.py +173 -56
  35. a_sync/primitives/__init__.py +14 -2
  36. a_sync/primitives/_debug.py +72 -18
  37. a_sync/primitives/_loggable.py +41 -10
  38. a_sync/primitives/locks/__init__.py +5 -2
  39. a_sync/primitives/locks/counter.py +107 -38
  40. a_sync/primitives/locks/event.py +21 -7
  41. a_sync/primitives/locks/prio_semaphore.py +262 -63
  42. a_sync/primitives/locks/semaphore.py +138 -89
  43. a_sync/primitives/queue.py +601 -60
  44. a_sync/sphinx/__init__.py +0 -1
  45. a_sync/sphinx/ext.py +160 -50
  46. a_sync/task.py +313 -112
  47. a_sync/utils/__init__.py +12 -6
  48. a_sync/utils/iterators.py +170 -50
  49. {ez_a_sync-0.22.14.dist-info → ez_a_sync-0.22.16.dist-info}/METADATA +1 -1
  50. ez_a_sync-0.22.16.dist-info/RECORD +74 -0
  51. {ez_a_sync-0.22.14.dist-info → ez_a_sync-0.22.16.dist-info}/WHEEL +1 -1
  52. tests/conftest.py +1 -2
  53. tests/executor.py +250 -9
  54. tests/fixtures.py +61 -32
  55. tests/test_abstract.py +22 -4
  56. tests/test_as_completed.py +54 -21
  57. tests/test_base.py +264 -19
  58. tests/test_cache.py +31 -15
  59. tests/test_decorator.py +54 -28
  60. tests/test_executor.py +31 -13
  61. tests/test_future.py +45 -8
  62. tests/test_gather.py +8 -2
  63. tests/test_helpers.py +2 -0
  64. tests/test_iter.py +55 -13
  65. tests/test_limiter.py +5 -3
  66. tests/test_meta.py +23 -9
  67. tests/test_modified.py +4 -1
  68. tests/test_semaphore.py +15 -8
  69. tests/test_singleton.py +28 -11
  70. tests/test_task.py +162 -36
  71. ez_a_sync-0.22.14.dist-info/RECORD +0 -74
  72. {ez_a_sync-0.22.14.dist-info → ez_a_sync-0.22.16.dist-info}/LICENSE.txt +0 -0
  73. {ez_a_sync-0.22.14.dist-info → ez_a_sync-0.22.16.dist-info}/top_level.txt +0 -0
tests/executor.py CHANGED
@@ -1,11 +1,252 @@
1
- def work():
2
- import time
3
- time.sleep(5)
1
+ import asyncio
2
+ import time
4
3
 
5
- from a_sync import ProcessPoolExecutor
4
+ import pytest
6
5
 
7
- @pytest.marks.asyncio
8
- async def test_executor():
9
- executor = ProcessPoolExecutor(6)
10
- await executor.run(work())
11
- await executor.submit(work())
6
+ from a_sync import ProcessPoolExecutor, ThreadPoolExecutor, PruningThreadPoolExecutor
7
+
8
+
9
+ @pytest.mark.asyncio
10
+ async def test_process_pool_executor_run():
11
+ """Tests the :class:`ProcessPoolExecutor` by running and submitting the work function asynchronously.
12
+
13
+ This test ensures that the `run` method of the `ProcessPoolExecutor` returns a coroutine
14
+ when executed with a synchronous function.
15
+
16
+ See Also:
17
+ - :meth:`ProcessPoolExecutor.run`
18
+ - :func:`asyncio.iscoroutine`
19
+
20
+ """
21
+ executor = ProcessPoolExecutor(1)
22
+ coro = executor.run(time.sleep, 0.1)
23
+ assert asyncio.iscoroutine(coro)
24
+ await coro
25
+
26
+
27
+ @pytest.mark.asyncio
28
+ async def test_thread_pool_executor_run():
29
+ """Tests the :class:`ThreadPoolExecutor` by running and submitting the work function asynchronously.
30
+
31
+ This test ensures that the `run` method of the `ThreadPoolExecutor` returns a coroutine
32
+ when executed with a synchronous function.
33
+
34
+ See Also:
35
+ - :meth:`ThreadPoolExecutor.run`
36
+ - :func:`asyncio.iscoroutine`
37
+
38
+ """
39
+ executor = ThreadPoolExecutor(1)
40
+ coro = executor.run(time.sleep, 0.1)
41
+ assert asyncio.iscoroutine(coro)
42
+ await coro
43
+
44
+
45
+ @pytest.mark.asyncio
46
+ async def test_pruning_thread_pool_executor_run():
47
+ """Tests the :class:`PruningThreadPoolExecutor` by running and submitting the work function asynchronously.
48
+
49
+ This test ensures that the `run` method of the `PruningThreadPoolExecutor` returns a coroutine
50
+ when executed with a synchronous function.
51
+
52
+ See Also:
53
+ - :meth:`PruningThreadPoolExecutor.run`
54
+ - :func:`asyncio.iscoroutine`
55
+
56
+ """
57
+ executor = PruningThreadPoolExecutor(1)
58
+ coro = executor.run(time.sleep, 0.1)
59
+ assert asyncio.iscoroutine(coro)
60
+ await coro
61
+
62
+
63
+ @pytest.mark.asyncio
64
+ async def test_process_pool_executor_submit():
65
+ """Tests the :class:`ProcessPoolExecutor` by submitting the work function.
66
+
67
+ This test ensures that the `submit` method of the `ProcessPoolExecutor` returns an
68
+ :class:`asyncio.Future` when executed with a synchronous function.
69
+
70
+ Note:
71
+ The `submit` method in this context returns an `asyncio.Future`, not a `concurrent.futures.Future`.
72
+ This is specific to the implementation of the executors in the `a_sync` library, which adapts the
73
+ behavior to integrate with the asyncio event loop.
74
+
75
+ See Also:
76
+ - :meth:`ProcessPoolExecutor.submit`
77
+ - :class:`asyncio.Future`
78
+
79
+ """
80
+ executor = ProcessPoolExecutor(1)
81
+ fut = executor.submit(time.sleep, 0.1)
82
+ assert isinstance(fut, asyncio.Future)
83
+ await fut
84
+
85
+
86
+ @pytest.mark.asyncio
87
+ async def test_thread_pool_executor_submit():
88
+ """Tests the :class:`ThreadPoolExecutor` by submitting the work function.
89
+
90
+ This test ensures that the `submit` method of the `ThreadPoolExecutor` returns an
91
+ :class:`asyncio.Future` when executed with a synchronous function.
92
+
93
+ Note:
94
+ The `submit` method in this context returns an `asyncio.Future`, not a `concurrent.futures.Future`.
95
+ This is specific to the implementation of the executors in the `a_sync` library, which adapts the
96
+ behavior to integrate with the asyncio event loop.
97
+
98
+ See Also:
99
+ - :meth:`ThreadPoolExecutor.submit`
100
+ - :class:`asyncio.Future`
101
+
102
+ """
103
+ executor = ThreadPoolExecutor(1)
104
+ fut = executor.submit(time.sleep, 0.1)
105
+ assert isinstance(fut, asyncio.Future)
106
+ await fut
107
+
108
+
109
+ @pytest.mark.asyncio
110
+ async def test_pruning_thread_pool_executor_submit():
111
+ """Tests the :class:`PruningThreadPoolExecutor` by submitting the work function.
112
+
113
+ This test ensures that the `submit` method of the `PruningThreadPoolExecutor` returns an
114
+ :class:`asyncio.Future` when executed with a synchronous function.
115
+
116
+ Note:
117
+ The `submit` method in this context returns an `asyncio.Future`, not a `concurrent.futures.Future`.
118
+ This is specific to the implementation of the executors in the `a_sync` library, which adapts the
119
+ behavior to integrate with the asyncio event loop.
120
+
121
+ See Also:
122
+ - :meth:`PruningThreadPoolExecutor.submit`
123
+ - :class:`asyncio.Future`
124
+
125
+ """
126
+ executor = PruningThreadPoolExecutor(1)
127
+ fut = executor.submit(time.sleep, 0.1)
128
+ assert isinstance(fut, asyncio.Future)
129
+ await fut
130
+
131
+
132
+ @pytest.mark.asyncio
133
+ async def test_process_pool_executor_sync_run():
134
+ """Tests the :class:`ProcessPoolExecutor` by running and submitting the work function synchronously.
135
+
136
+ This test ensures that the `run` method of the `ProcessPoolExecutor` returns a coroutine
137
+ when executed with a synchronous function.
138
+
139
+ See Also:
140
+ - :meth:`ProcessPoolExecutor.run`
141
+ - :func:`asyncio.iscoroutine`
142
+
143
+ """
144
+ executor = ProcessPoolExecutor(0)
145
+ coro = executor.run(time.sleep, 0.1)
146
+ assert asyncio.iscoroutine(coro)
147
+ await coro
148
+
149
+
150
+ @pytest.mark.asyncio
151
+ async def test_thread_pool_executor_sync_run():
152
+ """Tests the :class:`ThreadPoolExecutor` by running and submitting the work function synchronously.
153
+
154
+ This test ensures that the `run` method of the `ThreadPoolExecutor` returns a coroutine
155
+ when executed with a synchronous function.
156
+
157
+ See Also:
158
+ - :meth:`ThreadPoolExecutor.run`
159
+ - :func:`asyncio.iscoroutine`
160
+
161
+ """
162
+ executor = ThreadPoolExecutor(0)
163
+ coro = executor.run(time.sleep, 0.1)
164
+ assert asyncio.iscoroutine(coro)
165
+ await coro
166
+
167
+
168
+ @pytest.mark.asyncio
169
+ async def test_pruning_thread_pool_executor_sync_run():
170
+ """Tests the :class:`PruningThreadPoolExecutor` by running and submitting the work function synchronously.
171
+
172
+ This test ensures that the `run` method of the `PruningThreadPoolExecutor` returns a coroutine
173
+ when executed with a synchronous function.
174
+
175
+ See Also:
176
+ - :meth:`PruningThreadPoolExecutor.run`
177
+ - :func:`asyncio.iscoroutine`
178
+
179
+ """
180
+ executor = PruningThreadPoolExecutor(0)
181
+ coro = executor.run(time.sleep, 0.1)
182
+ assert asyncio.iscoroutine(coro)
183
+ await coro
184
+
185
+
186
+ @pytest.mark.asyncio
187
+ async def test_process_pool_executor_sync_submit():
188
+ """Tests the :class:`ProcessPoolExecutor` by submitting the work function synchronously.
189
+
190
+ This test ensures that the `submit` method of the `ProcessPoolExecutor` returns an
191
+ :class:`asyncio.Future` when executed with a synchronous function.
192
+
193
+ Note:
194
+ The `submit` method in this context returns an `asyncio.Future`, not a `concurrent.futures.Future`.
195
+ This is specific to the implementation of the executors in the `a_sync` library, which adapts the
196
+ behavior to integrate with the asyncio event loop.
197
+
198
+ See Also:
199
+ - :meth:`ProcessPoolExecutor.submit`
200
+ - :class:`asyncio.Future`
201
+
202
+ """
203
+ executor = ProcessPoolExecutor(0)
204
+ fut = executor.submit(time.sleep, 0.1)
205
+ assert isinstance(fut, asyncio.Future)
206
+ await fut
207
+
208
+
209
+ @pytest.mark.asyncio
210
+ async def test_thread_pool_executor_sync_submit():
211
+ """Tests the :class:`ThreadPoolExecutor` by submitting the work function synchronously.
212
+
213
+ This test ensures that the `submit` method of the `ThreadPoolExecutor` returns an
214
+ :class:`asyncio.Future` when executed with a synchronous function.
215
+
216
+ Note:
217
+ The `submit` method in this context returns an `asyncio.Future`, not a `concurrent.futures.Future`.
218
+ This is specific to the implementation of the executors in the `a_sync` library, which adapts the
219
+ behavior to integrate with the asyncio event loop.
220
+
221
+ See Also:
222
+ - :meth:`ThreadPoolExecutor.submit`
223
+ - :class:`asyncio.Future`
224
+
225
+ """
226
+ executor = ThreadPoolExecutor(0)
227
+ fut = executor.submit(time.sleep, 0.1)
228
+ assert isinstance(fut, asyncio.Future)
229
+ await fut
230
+
231
+
232
+ @pytest.mark.asyncio
233
+ async def test_pruning_thread_pool_executor_sync_submit():
234
+ """Tests the :class:`PruningThreadPoolExecutor` by submitting the work function synchronously.
235
+
236
+ This test ensures that the `submit` method of the `PruningThreadPoolExecutor` returns an
237
+ :class:`asyncio.Future` when executed with a synchronous function.
238
+
239
+ Note:
240
+ The `submit` method in this context returns an `asyncio.Future`, not a `concurrent.futures.Future`.
241
+ This is specific to the implementation of the executors in the `a_sync` library, which adapts the
242
+ behavior to integrate with the asyncio event loop.
243
+
244
+ See Also:
245
+ - :meth:`PruningThreadPoolExecutor.submit`
246
+ - :class:`asyncio.Future`
247
+
248
+ """
249
+ executor = PruningThreadPoolExecutor(0)
250
+ fut = executor.submit(time.sleep, 0.1)
251
+ assert isinstance(fut, asyncio.Future)
252
+ await fut
tests/fixtures.py CHANGED
@@ -1,4 +1,3 @@
1
-
2
1
  import asyncio
3
2
  import time
4
3
  from threading import current_thread, main_thread
@@ -11,97 +10,124 @@ from a_sync import ASyncBase
11
10
  from a_sync.a_sync._meta import ASyncMeta, ASyncSingletonMeta
12
11
  from a_sync.a_sync.singleton import ASyncGenericSingleton
13
12
 
14
- increment = pytest.mark.parametrize('i', range(10))
13
+ increment = pytest.mark.parametrize("i", range(10))
14
+
15
+
16
+ class WrongThreadError(Exception): ...
15
17
 
16
- class WrongThreadError(Exception):
17
- ...
18
18
 
19
19
  class TestClass(ASyncBase):
20
20
  def __init__(self, v: int, sync: bool = False):
21
21
  self.v = v
22
22
  self.sync = sync
23
-
23
+
24
24
  async def test_fn(self) -> int:
25
25
  if self.sync == False and main_thread() != current_thread():
26
- raise WrongThreadError('This should be running on an event loop in the main thread.')
26
+ raise WrongThreadError(
27
+ "This should be running on an event loop in the main thread."
28
+ )
27
29
  elif self.sync == True and main_thread() != current_thread():
28
- raise WrongThreadError('This should be awaited in the main thread')
30
+ raise WrongThreadError("This should be awaited in the main thread")
29
31
  return self.v
30
-
32
+
31
33
  @a_sync.aka.property
32
34
  async def test_property(self) -> int:
33
35
  if self.sync == False and main_thread() != current_thread():
34
- raise WrongThreadError('This should be running on an event loop in the main thread.')
36
+ raise WrongThreadError(
37
+ "This should be running on an event loop in the main thread."
38
+ )
35
39
  elif self.sync == True and main_thread() != current_thread():
36
- raise WrongThreadError('This should be awaited in the main thread')
40
+ raise WrongThreadError("This should be awaited in the main thread")
37
41
  return self.v * 2
38
-
42
+
39
43
  @a_sync.alias.cached_property
40
44
  async def test_cached_property(self) -> int:
41
45
  if self.sync == False and main_thread() != current_thread():
42
- raise WrongThreadError('This should be running on an event loop in the main thread.')
46
+ raise WrongThreadError(
47
+ "This should be running on an event loop in the main thread."
48
+ )
43
49
  elif self.sync == True and main_thread() != current_thread():
44
- raise WrongThreadError('This should be awaited in the main thread')
50
+ raise WrongThreadError("This should be awaited in the main thread")
45
51
  await asyncio.sleep(2)
46
52
  return self.v * 3
47
53
 
54
+
48
55
  class TestSync(ASyncBase):
49
56
  main = main_thread()
57
+
50
58
  def __init__(self, v: int, sync: bool):
51
59
  self.v = v
52
60
  self.sync = sync
53
-
61
+
54
62
  def test_fn(self) -> int:
55
63
  # Sync bound methods are actually async functions that are run in an executor and awaited
56
64
  if self.sync == False and main_thread() == current_thread():
57
- raise WrongThreadError('This should be running in an executor, not the main thread.')
65
+ raise WrongThreadError(
66
+ "This should be running in an executor, not the main thread."
67
+ )
58
68
  elif self.sync == True and main_thread() != current_thread():
59
- raise WrongThreadError('This should be running synchronously in the main thread')
69
+ raise WrongThreadError(
70
+ "This should be running synchronously in the main thread"
71
+ )
60
72
  return self.v
61
-
73
+
62
74
  @a_sync.aka.property
63
75
  def test_property(self) -> int:
64
76
  if self.sync == False and main_thread() == current_thread():
65
- raise WrongThreadError('This should be running in an executor, not the main thread.')
77
+ raise WrongThreadError(
78
+ "This should be running in an executor, not the main thread."
79
+ )
66
80
  if self.sync == True and main_thread() == current_thread():
67
81
  # Sync properties are actually async functions that are run in an executor and awaited
68
- raise WrongThreadError('This should be running in an executor, not the main thread.')
82
+ raise WrongThreadError(
83
+ "This should be running in an executor, not the main thread."
84
+ )
69
85
  return self.v * 2
70
-
86
+
71
87
  @a_sync.alias.cached_property
72
88
  def test_cached_property(self) -> int:
73
89
  if self.sync == False and main_thread() == current_thread():
74
- raise WrongThreadError('This should be running in an executor, not the main thread.')
90
+ raise WrongThreadError(
91
+ "This should be running in an executor, not the main thread."
92
+ )
75
93
  if self.sync == True and main_thread() == current_thread():
76
94
  # Sync properties are actually async functions that are run in an executor and awaited
77
- raise WrongThreadError('This should be running in an executor, not the main thread.')
95
+ raise WrongThreadError(
96
+ "This should be running in an executor, not the main thread."
97
+ )
78
98
  time.sleep(2)
79
99
  return self.v * 3
80
100
 
101
+
81
102
  class TestLimiter(TestClass):
82
103
  limiter = 1
83
-
104
+
105
+
84
106
  class TestInheritor(TestClass):
85
107
  pass
86
108
 
109
+
87
110
  class TestMeta(TestClass, metaclass=ASyncMeta):
88
111
  pass
89
112
 
113
+
90
114
  class TestSingleton(ASyncGenericSingleton, TestClass):
91
115
  runs_per_minute = 100
92
116
  pass
93
117
 
118
+
94
119
  class TestSingletonMeta(TestClass, metaclass=ASyncSingletonMeta):
95
120
  semaphore = 1
96
121
  pass
97
122
 
123
+
98
124
  class TestSemaphore(ASyncBase):
99
- #semaphore=1 # NOTE: this is detected propely by undecorated test_fn but not the properties
100
-
125
+ # semaphore=1 # NOTE: this is detected propely by undecorated test_fn but not the properties
126
+
101
127
  def __init__(self, v: int, sync: bool):
102
128
  self.v = v
103
129
  self.sync = sync
104
-
130
+
105
131
  # spec on class and function both working
106
132
  @a_sync.a_sync(semaphore=1)
107
133
  async def test_fn(self) -> int:
@@ -109,11 +135,11 @@ class TestSemaphore(ASyncBase):
109
135
  return self.v
110
136
 
111
137
  # spec on class, function, property all working
112
- @a_sync.aka.property('async', semaphore=1)
138
+ @a_sync.aka.property("async", semaphore=1)
113
139
  async def test_property(self) -> int:
114
140
  await asyncio.sleep(1)
115
141
  return self.v * 2
116
-
142
+
117
143
  # spec on class, function, property all working
118
144
  @a_sync.alias.cached_property(semaphore=50)
119
145
  async def test_cached_property(self) -> int:
@@ -121,7 +147,7 @@ class TestSemaphore(ASyncBase):
121
147
  return self.v * 3
122
148
 
123
149
 
124
- def _test_kwargs(fn, default: Literal['sync','async',None]):
150
+ def _test_kwargs(fn, default: Literal["sync", "async", None]):
125
151
  # force async
126
152
  assert asyncio.get_event_loop().run_until_complete(fn(sync=False)) == 2
127
153
  assert asyncio.get_event_loop().run_until_complete(fn(asynchronous=True)) == 2
@@ -132,18 +158,21 @@ def _test_kwargs(fn, default: Literal['sync','async',None]):
132
158
  assert asyncio.get_event_loop().run_until_complete(fn(asynchronous=False)) == 2
133
159
  assert fn(sync=True) == 2
134
160
  assert fn(asynchronous=False) == 2
135
- if default == 'sync':
161
+ if default == "sync":
136
162
  assert fn() == 2
137
- elif default == 'async':
163
+ elif default == "async":
138
164
  assert asyncio.get_event_loop().run_until_complete(fn()) == 2
139
165
 
166
+
140
167
  async def sample_task(n):
141
168
  await asyncio.sleep(0.01)
142
169
  return n
143
170
 
171
+
144
172
  async def timeout_task(n):
145
173
  await asyncio.sleep(0.1)
146
174
  return n
147
175
 
176
+
148
177
  async def sample_exc(n):
149
- raise ValueError("Sample error")
178
+ raise ValueError("Sample error")
tests/test_abstract.py CHANGED
@@ -1,17 +1,35 @@
1
-
2
1
  import sys
3
2
 
4
3
  import pytest
5
4
 
6
5
  from a_sync.a_sync.abstract import ASyncABC
7
6
 
8
- _methods = '__a_sync_default_mode__', '__a_sync_flag_name__', '__a_sync_flag_value__'
7
+ _methods = "__a_sync_default_mode__", "__a_sync_flag_name__", "__a_sync_flag_value__"
9
8
  if sys.version_info >= (3, 12):
10
9
  _MIDDLE = "without an implementation for abstract methods"
11
10
  _methods = (f"'{method}'" for method in _methods)
12
11
  else:
13
12
  _MIDDLE = "with abstract methods"
14
13
 
14
+
15
15
  def test_abc_direct_init():
16
- with pytest.raises(TypeError, match=f"Can't instantiate abstract class ASyncABC {_MIDDLE} {', '.join(_methods)}"):
17
- ASyncABC()
16
+ """Test that ASyncABC cannot be instantiated directly.
17
+
18
+ This test verifies that attempting to instantiate the abstract base class
19
+ `ASyncABC` raises a `TypeError`. This is expected behavior for abstract
20
+ base classes in Python, which require subclasses to implement all abstract
21
+ methods before instantiation.
22
+
23
+ Raises:
24
+ TypeError: If `ASyncABC` is instantiated without implementing abstract methods.
25
+
26
+ Example:
27
+ >>> from a_sync.a_sync.abstract import ASyncABC
28
+ >>> ASyncABC()
29
+ TypeError: Can't instantiate abstract class ASyncABC with abstract methods ...
30
+ """
31
+ with pytest.raises(
32
+ TypeError,
33
+ match=f"Can't instantiate abstract class ASyncABC {_MIDDLE} {', '.join(_methods)}",
34
+ ):
35
+ ASyncABC()
@@ -1,4 +1,3 @@
1
-
2
1
  import asyncio
3
2
 
4
3
  import a_sync
@@ -11,7 +10,10 @@ from tests.fixtures import sample_exc, sample_task, timeout_task
11
10
  async def test_as_completed_with_awaitables():
12
11
  tasks = [sample_task(i) for i in range(5)]
13
12
  results = [await result for result in a_sync.as_completed(tasks, aiter=False)]
14
- assert sorted(results) == list(range(5)), "Results should be in ascending order from 0 to 4"
13
+ assert sorted(results) == list(
14
+ range(5)
15
+ ), "Results should be in ascending order from 0 to 4"
16
+
15
17
 
16
18
  @pytest.mark.asyncio_cooperative
17
19
  async def test_as_completed_with_awaitables_aiter():
@@ -19,42 +21,61 @@ async def test_as_completed_with_awaitables_aiter():
19
21
  results = []
20
22
  async for result in a_sync.as_completed(tasks, aiter=True):
21
23
  results.append(result)
22
- assert sorted(results) == list(range(5)), "Results should be in ascending order from 0 to 4"
24
+ assert sorted(results) == list(
25
+ range(5)
26
+ ), "Results should be in ascending order from 0 to 4"
27
+
23
28
 
24
29
  @pytest.mark.asyncio_cooperative
25
30
  async def test_as_completed_with_mapping():
26
- tasks = {'task1': sample_task(1), 'task2': sample_task(2)}
31
+ tasks = {"task1": sample_task(1), "task2": sample_task(2)}
27
32
  results = {}
28
33
  for result in a_sync.as_completed(tasks, aiter=False):
29
34
  key, value = await result
30
35
  results[key] = value
31
- assert results == {'task1': 1, 'task2': 2}, "Results should match the input mapping"
36
+ assert results == {"task1": 1, "task2": 2}, "Results should match the input mapping"
37
+
32
38
 
33
39
  @pytest.mark.asyncio_cooperative
34
40
  async def test_as_completed_with_mapping_aiter():
35
- tasks = {'task1': sample_task(1), 'task2': sample_task(2)}
41
+ tasks = {"task1": sample_task(1), "task2": sample_task(2)}
36
42
  results = {}
37
43
  async for key, result in a_sync.as_completed(tasks, aiter=True):
38
44
  results[key] = result
39
- assert results == {'task1': 1, 'task2': 2}, "Results should match the input mapping"
45
+ assert results == {"task1": 1, "task2": 2}, "Results should match the input mapping"
46
+
40
47
 
41
48
  @pytest.mark.asyncio_cooperative
42
49
  async def test_as_completed_with_timeout():
43
50
  tasks = [timeout_task(i) for i in range(2)]
44
51
  with pytest.raises(asyncio.TimeoutError):
45
- [await result for result in a_sync.as_completed(tasks, aiter=False, timeout=0.05)]
52
+ [
53
+ await result
54
+ for result in a_sync.as_completed(tasks, aiter=False, timeout=0.05)
55
+ ]
56
+
46
57
 
47
58
  @pytest.mark.asyncio_cooperative
48
59
  async def test_as_completed_with_timeout_aiter():
49
60
  tasks = [timeout_task(i) for i in range(2)]
50
61
  with pytest.raises(asyncio.TimeoutError):
51
- [result async for result in a_sync.as_completed(tasks, aiter=True, timeout=0.05)]
62
+ [
63
+ result
64
+ async for result in a_sync.as_completed(tasks, aiter=True, timeout=0.05)
65
+ ]
66
+
52
67
 
53
68
  @pytest.mark.asyncio_cooperative
54
69
  async def test_as_completed_return_exceptions():
55
70
  tasks = [sample_exc(i) for i in range(1)]
56
- results = [await result for result in a_sync.as_completed(tasks, aiter=False, return_exceptions=True)]
57
- assert isinstance(results[0], ValueError), f"The result should be an exception {results}"
71
+ results = [
72
+ await result
73
+ for result in a_sync.as_completed(tasks, aiter=False, return_exceptions=True)
74
+ ]
75
+ assert isinstance(
76
+ results[0], ValueError
77
+ ), f"The result should be an exception {results}"
78
+
58
79
 
59
80
  @pytest.mark.asyncio_cooperative
60
81
  async def test_as_completed_return_exceptions_aiter():
@@ -64,11 +85,17 @@ async def test_as_completed_return_exceptions_aiter():
64
85
  results.append(result)
65
86
  assert isinstance(results[0], ValueError), "The result should be an exception"
66
87
 
88
+
67
89
  @pytest.mark.asyncio_cooperative
68
90
  async def test_as_completed_with_tqdm_disabled():
69
91
  tasks = [sample_task(i) for i in range(5)]
70
- results = [await result for result in a_sync.as_completed(tasks, aiter=False, tqdm=False)]
71
- assert sorted(results) == list(range(5)), "Results should be in ascending order from 0 to 4"
92
+ results = [
93
+ await result for result in a_sync.as_completed(tasks, aiter=False, tqdm=False)
94
+ ]
95
+ assert sorted(results) == list(
96
+ range(5)
97
+ ), "Results should be in ascending order from 0 to 4"
98
+
72
99
 
73
100
  @pytest.mark.asyncio_cooperative
74
101
  async def test_as_completed_with_tqdm_disabled_aiter():
@@ -76,23 +103,29 @@ async def test_as_completed_with_tqdm_disabled_aiter():
76
103
  results = []
77
104
  async for result in a_sync.as_completed(tasks, aiter=True, tqdm=False):
78
105
  results.append(result)
79
- assert sorted(results) == list(range(5)), "Results should be in ascending order from 0 to 4"
106
+ assert sorted(results) == list(
107
+ range(5)
108
+ ), "Results should be in ascending order from 0 to 4"
109
+
80
110
 
81
111
  @pytest.mark.asyncio_cooperative
82
112
  async def test_as_completed_with_mapping_and_return_exceptions():
83
- tasks = {'task1': sample_exc(1), 'task2': sample_task(2)}
113
+ tasks = {"task1": sample_exc(1), "task2": sample_task(2)}
84
114
  results = {}
85
115
  for result in a_sync.as_completed(tasks, return_exceptions=True, aiter=False):
86
116
  key, value = await result
87
117
  results[key] = value
88
- assert isinstance(results['task1'], ValueError), "Result should be ValueError"
89
- assert results['task2'] == 2, "Results should match the input mapping"
118
+ assert isinstance(results["task1"], ValueError), "Result should be ValueError"
119
+ assert results["task2"] == 2, "Results should match the input mapping"
120
+
90
121
 
91
122
  @pytest.mark.asyncio_cooperative
92
123
  async def test_as_completed_with_mapping_and_return_exceptions_aiter():
93
- tasks = {'task1': sample_exc(1), 'task2': sample_task(2)}
124
+ tasks = {"task1": sample_exc(1), "task2": sample_task(2)}
94
125
  results = {}
95
- async for key, result in a_sync.as_completed(tasks, return_exceptions=True, aiter=True):
126
+ async for key, result in a_sync.as_completed(
127
+ tasks, return_exceptions=True, aiter=True
128
+ ):
96
129
  results[key] = result
97
- assert isinstance(results['task1'], ValueError), "Result should be ValueError"
98
- assert results['task2'] == 2, "Results should match the input mapping"
130
+ assert isinstance(results["task1"], ValueError), "Result should be ValueError"
131
+ assert results["task2"] == 2, "Results should match the input mapping"