ez-a-sync 0.22.14__py3-none-any.whl → 0.22.15__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 +4 -3
  2. a_sync/__init__.py +30 -12
  3. a_sync/_smart.py +132 -28
  4. a_sync/_typing.py +56 -12
  5. a_sync/a_sync/__init__.py +35 -10
  6. a_sync/a_sync/_descriptor.py +74 -26
  7. a_sync/a_sync/_flags.py +14 -6
  8. a_sync/a_sync/_helpers.py +8 -7
  9. a_sync/a_sync/_kwargs.py +3 -2
  10. a_sync/a_sync/_meta.py +120 -28
  11. a_sync/a_sync/abstract.py +102 -28
  12. a_sync/a_sync/base.py +34 -16
  13. a_sync/a_sync/config.py +47 -13
  14. a_sync/a_sync/decorator.py +239 -117
  15. a_sync/a_sync/function.py +416 -146
  16. a_sync/a_sync/method.py +197 -59
  17. a_sync/a_sync/modifiers/__init__.py +47 -5
  18. a_sync/a_sync/modifiers/cache/__init__.py +46 -17
  19. a_sync/a_sync/modifiers/cache/memory.py +86 -20
  20. a_sync/a_sync/modifiers/limiter.py +52 -22
  21. a_sync/a_sync/modifiers/manager.py +98 -16
  22. a_sync/a_sync/modifiers/semaphores.py +48 -15
  23. a_sync/a_sync/property.py +383 -82
  24. a_sync/a_sync/singleton.py +1 -0
  25. a_sync/aliases.py +0 -1
  26. a_sync/asyncio/__init__.py +4 -1
  27. a_sync/asyncio/as_completed.py +177 -49
  28. a_sync/asyncio/create_task.py +31 -17
  29. a_sync/asyncio/gather.py +72 -52
  30. a_sync/asyncio/utils.py +3 -3
  31. a_sync/exceptions.py +78 -23
  32. a_sync/executor.py +118 -71
  33. a_sync/future.py +575 -158
  34. a_sync/iter.py +110 -50
  35. a_sync/primitives/__init__.py +14 -2
  36. a_sync/primitives/_debug.py +13 -13
  37. a_sync/primitives/_loggable.py +5 -4
  38. a_sync/primitives/locks/__init__.py +5 -2
  39. a_sync/primitives/locks/counter.py +38 -36
  40. a_sync/primitives/locks/event.py +21 -7
  41. a_sync/primitives/locks/prio_semaphore.py +182 -62
  42. a_sync/primitives/locks/semaphore.py +78 -77
  43. a_sync/primitives/queue.py +560 -58
  44. a_sync/sphinx/__init__.py +0 -1
  45. a_sync/sphinx/ext.py +160 -50
  46. a_sync/task.py +262 -97
  47. a_sync/utils/__init__.py +12 -6
  48. a_sync/utils/iterators.py +127 -43
  49. {ez_a_sync-0.22.14.dist-info → ez_a_sync-0.22.15.dist-info}/METADATA +1 -1
  50. ez_a_sync-0.22.15.dist-info/RECORD +74 -0
  51. {ez_a_sync-0.22.14.dist-info → ez_a_sync-0.22.15.dist-info}/WHEEL +1 -1
  52. tests/conftest.py +1 -2
  53. tests/executor.py +112 -9
  54. tests/fixtures.py +61 -32
  55. tests/test_abstract.py +7 -4
  56. tests/test_as_completed.py +54 -21
  57. tests/test_base.py +66 -17
  58. tests/test_cache.py +31 -15
  59. tests/test_decorator.py +54 -28
  60. tests/test_executor.py +8 -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 +15 -10
  70. tests/test_task.py +126 -28
  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.15.dist-info}/LICENSE.txt +0 -0
  73. {ez_a_sync-0.22.14.dist-info → ez_a_sync-0.22.15.dist-info}/top_level.txt +0 -0
tests/test_iter.py CHANGED
@@ -1,4 +1,3 @@
1
-
2
1
  import asyncio
3
2
  import contextlib
4
3
  import pytest
@@ -10,30 +9,35 @@ from a_sync.exceptions import SyncModeInAsyncContextError
10
9
  from a_sync.iter import ASyncIterable, ASyncIterator
11
10
 
12
11
 
13
-
14
12
  test_both = pytest.mark.parametrize("cls_to_test", [ASyncIterable, ASyncIterator])
15
13
 
14
+
16
15
  @pytest.fixture
17
16
  def async_generator():
18
17
  async def async_gen(i: int = 3):
19
18
  for i in range(i):
20
19
  yield i
20
+
21
21
  yield async_gen
22
22
 
23
+
23
24
  @pytest.fixture
24
25
  def async_generator_empty():
25
26
  async def async_gen_empty():
26
27
  if True:
27
28
  return
28
29
  yield
30
+
29
31
  yield async_gen_empty
30
32
 
33
+
31
34
  @pytest.fixture
32
35
  def async_error_generator():
33
36
  async def async_err_gen():
34
37
  yield 0
35
38
  yield 1
36
39
  raise ValueError("Simulated error")
40
+
37
41
  return async_err_gen
38
42
 
39
43
 
@@ -42,6 +46,7 @@ def test_wrap_types(cls_to_test, async_generator):
42
46
  assert isinstance(cls_to_test(async_generator()), cls_to_test)
43
47
  assert isinstance(cls_to_test.wrap(async_generator()), cls_to_test)
44
48
 
49
+
45
50
  @test_both
46
51
  def test_sync(cls_to_test, async_generator):
47
52
  # sourcery skip: identity-comprehension, list-comprehension
@@ -64,13 +69,17 @@ def test_sync(cls_to_test, async_generator):
64
69
  assert cls_to_test(async_generator()).materialized == [0, 1, 2]
65
70
  assert cls_to_test.wrap(async_generator()).materialized == [0, 1, 2]
66
71
 
72
+
67
73
  @test_both
68
74
  @pytest.mark.asyncio_cooperative
69
75
  async def test_async(cls_to_test, async_generator):
70
76
  ait = cls_to_test(async_generator())
71
77
 
72
78
  # comprehension
73
- with pytest.raises(SyncModeInAsyncContextError, match="The event loop is already running. Try iterating using `async for` instead of `for`."):
79
+ with pytest.raises(
80
+ SyncModeInAsyncContextError,
81
+ match="The event loop is already running. Try iterating using `async for` instead of `for`.",
82
+ ):
74
83
  list(ait)
75
84
  assert [i async for i in ait] == [0, 1, 2]
76
85
 
@@ -79,7 +88,10 @@ async def test_async(cls_to_test, async_generator):
79
88
  async for item in cls_to_test(async_generator()):
80
89
  result.append(item)
81
90
  assert result == [0, 1, 2]
82
- with pytest.raises(SyncModeInAsyncContextError, match="The event loop is already running. Try iterating using `async for` instead of `for`."):
91
+ with pytest.raises(
92
+ SyncModeInAsyncContextError,
93
+ match="The event loop is already running. Try iterating using `async for` instead of `for`.",
94
+ ):
83
95
  for _ in cls_to_test(async_generator()):
84
96
  pass
85
97
 
@@ -95,11 +107,15 @@ async def test_async(cls_to_test, async_generator):
95
107
  def test_sync_empty(cls_to_test, async_generator_empty):
96
108
  assert not list(cls_to_test(async_generator_empty()))
97
109
 
110
+
98
111
  @test_both
99
112
  @pytest.mark.asyncio_cooperative
100
113
  async def test_async_empty(cls_to_test, async_generator_empty):
101
114
  ait = cls_to_test(async_generator_empty())
102
- with pytest.raises(SyncModeInAsyncContextError, match="The event loop is already running. Try iterating using `async for` instead of `for`."):
115
+ with pytest.raises(
116
+ SyncModeInAsyncContextError,
117
+ match="The event loop is already running. Try iterating using `async for` instead of `for`.",
118
+ ):
103
119
  list(ait)
104
120
  assert not [i async for i in ait]
105
121
 
@@ -118,6 +134,7 @@ def test_sync_partial(cls_to_test, async_generator):
118
134
  remaining = list(iterator)
119
135
  assert remaining == [3, 4] if cls_to_test is ASyncIterator else [0, 1, 2, 3, 4]
120
136
 
137
+
121
138
  @test_both
122
139
  @pytest.mark.asyncio_cooperative
123
140
  async def test_async_partial(cls_to_test, async_generator):
@@ -146,6 +163,7 @@ def test_stop_iteration_sync(cls_to_test, async_generator):
146
163
  with pytest.raises(StopIteration):
147
164
  next(it)
148
165
 
166
+
149
167
  @test_both
150
168
  @pytest.mark.asyncio_cooperative
151
169
  async def test_stop_iteration_async(cls_to_test, async_generator):
@@ -162,15 +180,23 @@ async def test_stop_iteration_async(cls_to_test, async_generator):
162
180
 
163
181
  # Test decorator
164
182
 
183
+
165
184
  def test_aiterable_decorated_func_sync():
166
- with pytest.raises(TypeError, match="`async_iterable` must be an AsyncIterable. You passed "):
185
+ with pytest.raises(
186
+ TypeError, match="`async_iterable` must be an AsyncIterable. You passed "
187
+ ):
188
+
167
189
  @ASyncIterable.wrap
168
190
  async def decorated():
169
191
  yield 0
170
-
192
+
193
+
171
194
  @pytest.mark.asyncio_cooperative
172
195
  async def test_aiterable_decorated_func_async(async_generator):
173
- with pytest.raises(TypeError, match="`async_iterable` must be an AsyncIterable. You passed "):
196
+ with pytest.raises(
197
+ TypeError, match="`async_iterable` must be an AsyncIterable. You passed "
198
+ ):
199
+
174
200
  @ASyncIterable.wrap
175
201
  async def decorated():
176
202
  yield 0
@@ -181,16 +207,19 @@ def test_aiterator_decorated_func_sync(async_generator):
181
207
  async def decorated():
182
208
  async for i in async_generator():
183
209
  yield i
210
+
184
211
  retval = decorated()
185
212
  assert isinstance(retval, ASyncIterator)
186
213
  assert list(retval) == [0, 1, 2]
187
-
214
+
215
+
188
216
  @pytest.mark.asyncio_cooperative
189
217
  async def test_aiterator_decorated_func_async(async_generator):
190
218
  @ASyncIterator.wrap
191
219
  async def decorated():
192
220
  async for i in async_generator():
193
221
  yield i
222
+
194
223
  retval = decorated()
195
224
  assert isinstance(retval, ASyncIterator)
196
225
  assert await retval == [0, 1, 2]
@@ -198,14 +227,17 @@ async def test_aiterator_decorated_func_async(async_generator):
198
227
 
199
228
  def test_aiterable_decorated_method_sync():
200
229
  with pytest.raises(TypeError, match=""):
230
+
201
231
  class Test:
202
232
  @ASyncIterable.wrap
203
233
  async def decorated(self):
204
234
  yield 0
205
-
235
+
236
+
206
237
  @pytest.mark.asyncio_cooperative
207
238
  async def test_aiterable_decorated_method_async():
208
239
  with pytest.raises(TypeError, match=""):
240
+
209
241
  class Test:
210
242
  @ASyncIterable.wrap
211
243
  async def decorated(self):
@@ -218,10 +250,12 @@ def test_aiterator_decorated_method_sync(async_generator):
218
250
  async def decorated(self):
219
251
  async for i in async_generator():
220
252
  yield i
253
+
221
254
  retval = Test().decorated()
222
255
  assert isinstance(retval, ASyncIterator)
223
256
  assert list(retval) == [0, 1, 2]
224
-
257
+
258
+
225
259
  @pytest.mark.asyncio_cooperative
226
260
  async def test_aiterator_decorated_method_async(async_generator):
227
261
  class Test:
@@ -229,10 +263,11 @@ async def test_aiterator_decorated_method_async(async_generator):
229
263
  async def decorated(self):
230
264
  async for i in async_generator():
231
265
  yield i
266
+
232
267
  retval = Test().decorated()
233
268
  assert isinstance(retval, ASyncIterator)
234
269
  assert await retval == [0, 1, 2]
235
-
270
+
236
271
 
237
272
  @test_both
238
273
  def test_sync_error_handling(cls_to_test, async_error_generator):
@@ -243,6 +278,7 @@ def test_sync_error_handling(cls_to_test, async_error_generator):
243
278
  # we still got some results though
244
279
  assert results == [0, 1]
245
280
 
281
+
246
282
  @test_both
247
283
  @pytest.mark.asyncio_cooperative
248
284
  async def test_async_error_handling(cls_to_test, async_error_generator):
@@ -257,11 +293,13 @@ async def test_async_error_handling(cls_to_test, async_error_generator):
257
293
 
258
294
  # Test failures
259
295
 
296
+
260
297
  @test_both
261
298
  def test_sync_with_iterable(cls_to_test):
262
299
  with pytest.raises(TypeError):
263
300
  cls_to_test([0, 1, 2])
264
301
 
302
+
265
303
  @test_both
266
304
  @pytest.mark.asyncio_cooperative
267
305
  async def test_async_with_iterable(cls_to_test):
@@ -271,24 +309,28 @@ async def test_async_with_iterable(cls_to_test):
271
309
 
272
310
  # Type check dunder methods
273
311
 
312
+
274
313
  def test_async_iterable_iter_method(async_generator):
275
314
  ait = ASyncIterable(async_generator())
276
315
  iterator = iter(ait)
277
316
  assert isinstance(iterator, Iterator)
278
317
 
318
+
279
319
  def test_async_iterator_iter_method(async_generator):
280
320
  ait = ASyncIterator(async_generator())
281
321
  iterator = iter(ait)
282
322
  assert iterator is ait # Should return self
283
323
 
324
+
284
325
  @pytest.mark.asyncio_cooperative
285
326
  async def test_async_aiter_method(async_generator):
286
327
  ait = ASyncIterable(async_generator())
287
328
  async_iterator = ait.__aiter__()
288
329
  assert isinstance(async_iterator, AsyncIterator)
289
330
 
331
+
290
332
  @pytest.mark.asyncio_cooperative
291
333
  async def test_async_iterator_aiter_method(async_generator):
292
334
  ait = ASyncIterator(async_generator())
293
335
  async_iterator = ait.__aiter__()
294
- assert async_iterator is ait # Should return self
336
+ assert async_iterator is ait # Should return self
tests/test_limiter.py CHANGED
@@ -1,4 +1,3 @@
1
-
2
1
  import pytest
3
2
  from time import time
4
3
  from tests.fixtures import TestLimiter, increment
@@ -9,18 +8,21 @@ from tests.fixtures import TestLimiter, increment
9
8
  # Maybe a problem with test suite interaction?
10
9
  # - semaphore modifier works fine with integer inputs
11
10
 
11
+
12
12
  @increment
13
13
  @pytest.mark.asyncio_cooperative
14
14
  async def test_semaphore(i: int):
15
15
  instance = TestLimiter(i, sync=False)
16
16
  assert await instance.test_fn() == i
17
-
17
+
18
+
18
19
  @increment
19
20
  @pytest.mark.asyncio_cooperative
20
21
  async def test_semaphore_property(i: int):
21
22
  instance = TestLimiter(i, sync=False)
22
23
  assert await instance.test_property == i * 2
23
-
24
+
25
+
24
26
  @increment
25
27
  @pytest.mark.asyncio_cooperative
26
28
  async def test_semaphore_cached_property(i: int):
tests/test_meta.py CHANGED
@@ -9,7 +9,8 @@ from a_sync.a_sync.property import HiddenMethod
9
9
  from a_sync.a_sync.singleton import ASyncGenericSingleton
10
10
  from tests.fixtures import TestSingleton, TestSingletonMeta, increment
11
11
 
12
- classes = pytest.mark.parametrize('cls', [TestSingleton, TestSingletonMeta])
12
+ classes = pytest.mark.parametrize("cls", [TestSingleton, TestSingletonMeta])
13
+
13
14
 
14
15
  @classes
15
16
  @increment
@@ -24,7 +25,9 @@ def test_singleton_meta_sync(cls: type, i: int):
24
25
  assert sync_instance.test_cached_property == 0
25
26
  assert isinstance(sync_instance.test_cached_property, int)
26
27
  duration = time.time() - start
27
- assert duration < 3, "There is a 2 second sleep in 'test_cached_property' but it should only run once."
28
+ assert (
29
+ duration < 3
30
+ ), "There is a 2 second sleep in 'test_cached_property' but it should only run once."
28
31
 
29
32
  # Can we override with kwargs?
30
33
  val = asyncio.get_event_loop().run_until_complete(sync_instance.test_fn(sync=False))
@@ -41,9 +44,17 @@ def test_singleton_meta_sync(cls: type, i: int):
41
44
  getter_coro = getter()
42
45
  assert asyncio.get_event_loop().run_until_complete(getter_coro) == 0
43
46
  # Can we override them too?
44
- assert asyncio.get_event_loop().run_until_complete(sync_instance.__test_cached_property__(sync=False)) == 0
47
+ assert (
48
+ asyncio.get_event_loop().run_until_complete(
49
+ sync_instance.__test_cached_property__(sync=False)
50
+ )
51
+ == 0
52
+ )
45
53
  duration = time.time() - start
46
- assert duration < 3, "There is a 2 second sleep in 'test_cached_property' but it should only run once."
54
+ assert (
55
+ duration < 3
56
+ ), "There is a 2 second sleep in 'test_cached_property' but it should only run once."
57
+
47
58
 
48
59
  @classes
49
60
  @increment
@@ -59,12 +70,14 @@ async def test_singleton_meta_async(cls: type, i: int):
59
70
  assert await async_instance.test_cached_property == 0
60
71
  assert isinstance(await async_instance.test_cached_property, int)
61
72
  duration = time.time() - start
62
- assert duration < 3, "There is a 2 second sleep in 'test_cached_property' but it should only run once."
73
+ assert (
74
+ duration < 3
75
+ ), "There is a 2 second sleep in 'test_cached_property' but it should only run once."
63
76
 
64
77
  # Can we override with kwargs?
65
78
  with pytest.raises(RuntimeError):
66
79
  async_instance.test_fn(sync=True)
67
-
80
+
68
81
  # Can we access hidden methods for properties?
69
82
  assert await async_instance.__test_property__() == 0
70
83
  assert await async_instance.__test_cached_property__() == 0
@@ -73,24 +86,25 @@ async def test_singleton_meta_async(cls: type, i: int):
73
86
  async_instance.__test_cached_property__(sync=True)
74
87
 
75
88
 
76
-
77
89
  class TestUnspecified(ASyncGenericSingleton):
78
90
  def __init__(self, sync=True):
79
91
  self.sync = sync
80
92
 
93
+
81
94
  def test_singleton_unspecified():
82
95
  obj = TestUnspecified()
83
96
  assert obj.sync == True
84
97
  obj.test_attr = True
85
98
  newobj = TestUnspecified()
86
- assert hasattr(newobj, 'test_attr')
99
+ assert hasattr(newobj, "test_attr")
87
100
 
88
101
  assert TestUnspecified(sync=True).sync == True
89
102
  assert TestUnspecified(sync=False).sync == False
90
103
 
104
+
91
105
  def test_singleton_switching():
92
106
  obj = TestUnspecified()
93
107
  assert obj.sync == True
94
108
  obj.test_attr = True
95
109
  newobj = TestUnspecified(sync=False)
96
- assert not hasattr(newobj, 'test_attr')
110
+ assert not hasattr(newobj, "test_attr")
tests/test_modified.py CHANGED
@@ -1,16 +1,19 @@
1
-
2
1
  import a_sync
3
2
 
3
+
4
4
  @a_sync.a_sync
5
5
  def sync_def():
6
6
  pass
7
7
 
8
+
8
9
  @a_sync.a_sync
9
10
  async def async_def():
10
11
  pass
11
12
 
13
+
12
14
  def test_sync_def_repr():
13
15
  assert sync_def.__name__ == "sync_def"
14
16
 
17
+
15
18
  def test_async_def_repr():
16
19
  assert async_def.__name__ == "async_def"
tests/test_semaphore.py CHANGED
@@ -1,4 +1,3 @@
1
-
2
1
  import pytest
3
2
  from time import time
4
3
  from tests.fixtures import TestSemaphore, increment
@@ -12,30 +11,38 @@ from tests.fixtures import TestSemaphore, increment
12
11
 
13
12
  instance = TestSemaphore(1, sync=False)
14
13
 
14
+
15
15
  @increment
16
16
  @pytest.mark.asyncio_cooperative
17
17
  async def test_semaphore(i: int):
18
18
  start = time()
19
19
  assert await instance.test_fn() == 1
20
20
  duration = time() - start
21
- assert i < 3 or duration > i # There is a 1 second sleep in this fn. If the semaphore is not working, all tests will complete in 1 second.
22
-
23
-
21
+ assert (
22
+ i < 3 or duration > i
23
+ ) # There is a 1 second sleep in this fn. If the semaphore is not working, all tests will complete in 1 second.
24
+
25
+
24
26
  @increment
25
27
  @pytest.mark.asyncio_cooperative
26
28
  async def test_semaphore_property(i: int):
27
29
  start = time()
28
30
  assert await instance.test_property == 2
29
31
  duration = time() - start
30
- assert i < 3 or duration > i # There is a 1 second sleep in this fn. If the semaphore is not working, all tests will complete in 1 second.
31
-
32
+ assert (
33
+ i < 3 or duration > i
34
+ ) # There is a 1 second sleep in this fn. If the semaphore is not working, all tests will complete in 1 second.
35
+
36
+
32
37
  @increment
33
38
  @pytest.mark.asyncio_cooperative
34
39
  async def test_semaphore_cached_property(i: int):
35
40
  start = time()
36
41
  assert await instance.test_cached_property == 3
37
42
  duration = time() - start
38
- # There is a 1 second sleep in this fn but a semaphore override with a value of 50.
43
+ # There is a 1 second sleep in this fn but a semaphore override with a value of 50.
39
44
  # You can tell it worked correctly because the class-defined semaphore value is just one, whch would cause this test to fail if it were used.
40
45
  # If the override is not working, all tests will complete in just over 1 second.
41
- assert i == 1 or duration < 1.4 # We increased the threshold from 1.05 to 1.4 to help tests pass on slow github runners
46
+ assert (
47
+ i == 1 or duration < 1.4
48
+ ) # We increased the threshold from 1.05 to 1.4 to help tests pass on slow github runners
tests/test_singleton.py CHANGED
@@ -1,20 +1,25 @@
1
-
2
1
  from a_sync.a_sync.singleton import ASyncGenericSingleton
3
2
 
3
+
4
4
  def test_flag_predefined():
5
5
  """We had a failure case where the subclass implementation assigned the flag value to the class and did not allow user to determine at init time"""
6
+
6
7
  class Test(ASyncGenericSingleton):
7
- sync=True
8
- def __init__(self):
9
- ...
8
+ sync = True
9
+
10
+ def __init__(self): ...
11
+
10
12
  Test()
11
- class TestInherit(Test):
12
- ...
13
+
14
+ class TestInherit(Test): ...
15
+
13
16
  TestInherit()
14
17
 
15
18
  class Test(ASyncGenericSingleton):
16
- sync=False
19
+ sync = False
20
+
17
21
  Test()
18
- class TestInherit(Test):
19
- ...
20
- TestInherit()
22
+
23
+ class TestInherit(Test): ...
24
+
25
+ TestInherit()