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
@@ -2,9 +2,14 @@
2
2
  # mypy: disable-error-code=misc
3
3
  from a_sync._typing import *
4
4
  from a_sync.a_sync import _flags, config
5
- from a_sync.a_sync.function import (ASyncDecorator, ASyncFunction, ASyncDecoratorAsyncDefault,
6
- ASyncDecoratorSyncDefault, ASyncFunctionAsyncDefault,
7
- ASyncFunctionSyncDefault)
5
+ from a_sync.a_sync.function import (
6
+ ASyncDecorator,
7
+ ASyncFunction,
8
+ ASyncDecoratorAsyncDefault,
9
+ ASyncDecoratorSyncDefault,
10
+ ASyncFunctionAsyncDefault,
11
+ ASyncFunctionSyncDefault,
12
+ )
8
13
 
9
14
  ########################
10
15
  # The a_sync decorator #
@@ -18,36 +23,78 @@ from a_sync.a_sync.function import (ASyncDecorator, ASyncFunction, ASyncDecorato
18
23
  # async def some_fn():
19
24
  # pass
20
25
 
26
+
21
27
  @overload
22
28
  def a_sync(
23
29
  default: Literal["async"],
24
30
  **modifiers: Unpack[ModifierKwargs],
25
- ) -> ASyncDecoratorAsyncDefault:...
31
+ ) -> ASyncDecoratorAsyncDefault:
32
+ """
33
+ Creates an asynchronous default decorator.
34
+
35
+ Args:
36
+ default: Specifies the default execution mode as 'async'.
37
+ **modifiers: Additional keyword arguments to modify the behavior of the decorated function.
38
+ """
39
+
26
40
 
27
41
  @overload
28
42
  def a_sync(
29
43
  default: Literal["sync"],
30
44
  **modifiers: Unpack[ModifierKwargs],
31
- ) -> ASyncDecoratorSyncDefault:...
45
+ ) -> ASyncDecoratorSyncDefault:
46
+ """
47
+ Creates a synchronous default decorator.
48
+
49
+ Args:
50
+ default: Specifies the default execution mode as 'sync'.
51
+ **modifiers: Additional keyword arguments to modify the behavior of the decorated function.
52
+ """
53
+
32
54
 
33
55
  @overload
34
56
  def a_sync(
35
57
  **modifiers: Unpack[ModifierKwargs],
36
- ) -> ASyncDecorator:...
58
+ ) -> ASyncDecorator:
59
+ """
60
+ Creates a decorator with no default execution mode specified.
37
61
 
38
- @overload # async def, None default
39
- def a_sync(
62
+ Args:
63
+ **modifiers: Additional keyword arguments to modify the behavior of the decorated function.
64
+ """
65
+
66
+
67
+ @overload # async def, None default
68
+ def a_sync(
40
69
  coro_fn: CoroFn[P, T],
41
70
  default: Literal[None] = None,
42
71
  **modifiers: Unpack[ModifierKwargs],
43
- ) -> ASyncFunctionAsyncDefault[P, T]:...
72
+ ) -> ASyncFunctionAsyncDefault[P, T]:
73
+ """
74
+ Decorates an asynchronous function with no default execution mode specified.
75
+
76
+ Args:
77
+ coro_fn: The coroutine function to be decorated.
78
+ default: Specifies no default execution mode.
79
+ **modifiers: Additional keyword arguments to modify the behavior of the decorated function.
80
+ """
81
+
44
82
 
45
- @overload # sync def none default
46
- def a_sync(
83
+ @overload # sync def none default
84
+ def a_sync(
47
85
  coro_fn: SyncFn[P, T],
48
86
  default: Literal[None] = None,
49
87
  **modifiers: Unpack[ModifierKwargs],
50
- ) -> ASyncFunctionSyncDefault[P, T]:...
88
+ ) -> ASyncFunctionSyncDefault[P, T]:
89
+ """
90
+ Decorates a synchronous function with no default execution mode specified.
91
+
92
+ Args:
93
+ coro_fn: The synchronous function to be decorated.
94
+ default: Specifies no default execution mode.
95
+ **modifiers: Additional keyword arguments to modify the behavior of the decorated function.
96
+ """
97
+
51
98
 
52
99
  # @a_sync(default='async')
53
100
  # def some_fn():
@@ -59,51 +106,108 @@ def a_sync(
59
106
  #
60
107
  # NOTE These should output a decorator that will be applied to 'some_fn'
61
108
 
62
- @overload
63
- def a_sync(
109
+
110
+ @overload
111
+ def a_sync(
64
112
  coro_fn: Literal[None],
65
- default: Literal['async'],
113
+ default: Literal["async"],
66
114
  **modifiers: Unpack[ModifierKwargs],
67
- ) -> ASyncDecoratorAsyncDefault:...
115
+ ) -> ASyncDecoratorAsyncDefault:
116
+ """
117
+ Creates an asynchronous default decorator with no function specified.
118
+
119
+ Args:
120
+ coro_fn: Specifies no function.
121
+ default: Specifies the default execution mode as 'async'.
122
+ **modifiers: Additional keyword arguments to modify the behavior of the decorated function.
123
+ """
124
+
68
125
 
69
- @overload # if you try to use default as the only arg
70
- def a_sync(
71
- coro_fn: Literal['async'],
126
+ @overload # if you try to use default as the only arg
127
+ def a_sync(
128
+ coro_fn: Literal["async"],
72
129
  default: Literal[None],
73
130
  **modifiers: Unpack[ModifierKwargs],
74
- ) -> ASyncDecoratorAsyncDefault:...
131
+ ) -> ASyncDecoratorAsyncDefault:
132
+ """
133
+ Creates an asynchronous default decorator with no default execution mode specified.
134
+
135
+ Args:
136
+ coro_fn: Specifies the default execution mode as 'async'.
137
+ default: Specifies no default execution mode.
138
+ **modifiers: Additional keyword arguments to modify the behavior of the decorated function.
139
+ """
140
+
75
141
 
76
142
  # a_sync(some_fn, default='async')
77
143
 
78
- @overload # async def, async default
79
- def a_sync(
144
+
145
+ @overload # async def, async default
146
+ def a_sync(
80
147
  coro_fn: CoroFn[P, T],
81
- default: Literal['async'],
148
+ default: Literal["async"],
82
149
  **modifiers: Unpack[ModifierKwargs],
83
- ) -> ASyncFunctionAsyncDefault[P, T]:...
150
+ ) -> ASyncFunctionAsyncDefault[P, T]:
151
+ """
152
+ Decorates an asynchronous function with an asynchronous default execution mode.
153
+
154
+ Args:
155
+ coro_fn: The coroutine function to be decorated.
156
+ default: Specifies the default execution mode as 'async'.
157
+ **modifiers: Additional keyword arguments to modify the behavior of the decorated function.
158
+ """
159
+
84
160
 
85
- @overload # sync def async default
86
- def a_sync(
161
+ @overload # sync def async default
162
+ def a_sync(
87
163
  coro_fn: SyncFn[P, T],
88
- default: Literal['async'],
164
+ default: Literal["async"],
89
165
  **modifiers: Unpack[ModifierKwargs],
90
- ) -> ASyncFunctionAsyncDefault[P, T]:...
166
+ ) -> ASyncFunctionAsyncDefault[P, T]:
167
+ """
168
+ Decorates a synchronous function with an asynchronous default execution mode.
169
+
170
+ Args:
171
+ coro_fn: The synchronous function to be decorated.
172
+ default: Specifies the default execution mode as 'async'.
173
+ **modifiers: Additional keyword arguments to modify the behavior of the decorated function.
174
+ """
175
+
91
176
 
92
177
  # a_sync(some_fn, default='sync')
93
178
 
94
- @overload # async def, sync default
95
- def a_sync(
179
+
180
+ @overload # async def, sync default
181
+ def a_sync(
96
182
  coro_fn: CoroFn[P, T],
97
- default: Literal['sync'],
183
+ default: Literal["sync"],
98
184
  **modifiers: Unpack[ModifierKwargs],
99
- ) -> ASyncFunctionSyncDefault:...
185
+ ) -> ASyncFunctionSyncDefault:
186
+ """
187
+ Decorates an asynchronous function with a synchronous default execution mode.
100
188
 
101
- @overload # sync def sync default
102
- def a_sync(
189
+ Args:
190
+ coro_fn: The coroutine function to be decorated.
191
+ default: Specifies the default execution mode as 'sync'.
192
+ **modifiers: Additional keyword arguments to modify the behavior of the decorated function.
193
+ """
194
+
195
+
196
+ @overload # sync def sync default
197
+ def a_sync(
103
198
  coro_fn: SyncFn[P, T],
104
- default: Literal['sync'],
199
+ default: Literal["sync"],
105
200
  **modifiers: Unpack[ModifierKwargs],
106
- ) -> ASyncFunctionSyncDefault:...
201
+ ) -> ASyncFunctionSyncDefault:
202
+ """
203
+ Decorates a synchronous function with a synchronous default execution mode.
204
+
205
+ Args:
206
+ coro_fn: The synchronous function to be decorated.
207
+ default: Specifies the default execution mode as 'sync'.
208
+ **modifiers: Additional keyword arguments to modify the behavior of the decorated function.
209
+ """
210
+
107
211
 
108
212
  # @a_sync(default='sync')
109
213
  # def some_fn():
@@ -115,32 +219,62 @@ def a_sync(
115
219
  #
116
220
  # NOTE These should output a decorator that will be applied to 'some_fn'
117
221
 
118
- @overload
119
- def a_sync(
222
+
223
+ @overload
224
+ def a_sync(
120
225
  coro_fn: Literal[None],
121
- default: Literal['sync'],
226
+ default: Literal["sync"],
122
227
  **modifiers: Unpack[ModifierKwargs],
123
- ) -> ASyncDecoratorSyncDefault:...
228
+ ) -> ASyncDecoratorSyncDefault:
229
+ """
230
+ Creates a synchronous default decorator with no function specified.
231
+
232
+ Args:
233
+ coro_fn: Specifies no function.
234
+ default: Specifies the default execution mode as 'sync'.
235
+ **modifiers: Additional keyword arguments to modify the behavior of the decorated function.
236
+ """
124
237
 
125
- @overload # if you try to use default as the only arg
126
- def a_sync(
127
- coro_fn: Literal['sync'],
238
+
239
+ @overload # if you try to use default as the only arg
240
+ def a_sync(
241
+ coro_fn: Literal["sync"],
128
242
  default: Literal[None] = None,
129
243
  **modifiers: Unpack[ModifierKwargs],
130
- ) -> ASyncDecoratorSyncDefault:...
244
+ ) -> ASyncDecoratorSyncDefault:
245
+ """
246
+ Creates a synchronous default decorator with no default execution mode specified.
247
+
248
+ Args:
249
+ coro_fn: Specifies the default execution mode as 'sync'.
250
+ default: Specifies no default execution mode.
251
+ **modifiers: Additional keyword arguments to modify the behavior of the decorated function.
252
+ """
131
253
 
132
- @overload # if you try to use default as the only arg
133
- def a_sync(
134
- coro_fn: Literal['sync'],
254
+
255
+ @overload # if you try to use default as the only arg
256
+ def a_sync(
257
+ coro_fn: Literal["sync"],
135
258
  default: Literal[None],
136
259
  **modifiers: Unpack[ModifierKwargs],
137
- ) -> ASyncDecoratorSyncDefault:...
138
-
260
+ ) -> ASyncDecoratorSyncDefault:
261
+ """
262
+ Creates a synchronous default decorator with no default execution mode specified.
263
+
264
+ Args:
265
+ coro_fn: Specifies the default execution mode as 'sync'.
266
+ default: Specifies no default execution mode.
267
+ **modifiers: Additional keyword arguments to modify the behavior of the decorated function.
268
+ """
269
+
270
+
139
271
  # catchall
140
- def a_sync(
272
+ def a_sync(
141
273
  coro_fn: Optional[AnyFn[P, T]] = None,
142
274
  default: DefaultMode = config.DEFAULT_MODE,
143
- **modifiers: Unpack[ModifierKwargs], # default values are set by passing these kwargs into a ModifierManager object.
275
+ **modifiers: Unpack[
276
+ ModifierKwargs
277
+ ], # default values are set by passing these kwargs into a ModifierManager object.
144
278
  ) -> Union[ASyncDecorator, ASyncFunction[P, T]]:
145
279
  """
146
280
  A versatile decorator that enables both synchronous and asynchronous execution of functions.
@@ -155,97 +289,84 @@ def a_sync(
155
289
  If None, the mode is inferred from the decorated function type.
156
290
  **modifiers: Additional keyword arguments to modify the behavior of the decorated function.
157
291
  See :class:`ModifierKwargs` for available options.
158
-
292
+
159
293
  Modifiers:
160
- lib defaults:
161
- async settings
162
- cache_type: CacheType = None, - This can be None or 'memory'. 'memory' is a lru cache which can be modified with the 'cache_typed','ram_cache_maxsize','ram_cache_ttl' modifiers.
163
- cache_typed: bool = False, - Set to True if you want types considered treated for cache keys. ie with cache_typed=True, Decimal(0) and 0 will be considered separate keys.
164
- ram_cache_maxsize: Optional[int] = -1, - The maxsize for your lru cache. None if cache is unbounded. If you set this value without specifying a cache type, 'memory' will automatically be applied.
165
- ram_cache_ttl: Optional[int] = None, - The ttl for items in your lru cache. Set to None. If you set this value without specifying a cache type, 'memory' will automatically be applied.
166
- runs_per_minute: Optional[int] = None, - Setting this value enables a rate limiter for the decorated function.
167
- semaphore: SemaphoreSpec = None, - drop in a Semaphore for your async defined functions.
168
- sync settings
169
- executor: Executor = config.default_sync_executor
170
-
171
- Returns:
172
- An :class:`~ASyncDecorator` if used as a decorator factory, or an :class:`~ASyncFunction`
173
- if used directly on a function.
294
+ The following modifiers can be used to customize the behavior of the decorator:
295
+
296
+ - cache_type: Can be None or 'memory'. 'memory' is an LRU cache which can be modified with
297
+ the 'cache_typed', 'ram_cache_maxsize', and 'ram_cache_ttl' modifiers.
298
+ - cache_typed: Set to True if you want types considered for cache keys. For example, with
299
+ cache_typed=True, Decimal(0) and 0 will be considered separate keys.
300
+ - ram_cache_maxsize: The max size for your LRU cache. None if the cache is unbounded. If you
301
+ set this value without specifying a cache type, 'memory' will automatically be applied.
302
+ - ram_cache_ttl: The TTL for items in your LRU cache. Set to None. If you set this value
303
+ without specifying a cache type, 'memory' will automatically be applied.
304
+ - runs_per_minute: Setting this value enables a rate limiter for the decorated function.
305
+ - semaphore: Drop in a Semaphore for your async defined functions.
306
+ - executor: The executor for the synchronous function. Set to the library's default of
307
+ config.default_sync_executor.
174
308
 
175
309
  Examples:
176
310
  The decorator can be used in several ways.
177
311
 
178
312
  1. As a simple decorator:
179
- ```python
180
- >>> @a_sync
181
- ... async def some_async_fn():
182
- ... return True
183
- >>> await some_fn()
184
- True
185
- >>> some_fn(sync=True)
186
- True
187
- ```
188
- ```
189
- >>> @a_sync
190
- ... def some_sync_fn():
191
- ... return True
192
- >>> some_sync_fn()
193
- True
194
- >>> some_sync_fn(sync=False)
195
- <coroutine object some_sync_fn at 0x12345678>
196
- ```
313
+ >>> @a_sync
314
+ ... async def some_async_fn():
315
+ ... return True
316
+ >>> await some_fn()
317
+ True
318
+ >>> some_fn(sync=True)
319
+ True
320
+
321
+ >>> @a_sync
322
+ ... def some_sync_fn():
323
+ ... return True
324
+ >>> some_sync_fn()
325
+ True
326
+ >>> some_sync_fn(sync=False)
327
+ <coroutine object some_sync_fn at 0x12345678>
197
328
 
198
329
  2. As a decorator with default mode specified:
199
- ```python
200
- >>> @a_sync(default='sync')
201
- ... async def some_fn():
202
- ... return True
203
- ...
204
- >>> some_fn()
205
- True
206
- ```
330
+ >>> @a_sync(default='sync')
331
+ ... async def some_fn():
332
+ ... return True
333
+ ...
334
+ >>> some_fn()
335
+ True
207
336
 
208
337
  3. As a decorator with modifiers:
209
- ```python
210
- >>> @a_sync(cache_type='memory', runs_per_minute=60)
211
- ... async def some_fn():
212
- ... return True
213
- ...
214
- >>> some_fn(sync=True)
215
- True
216
- ```
338
+ >>> @a_sync(cache_type='memory', runs_per_minute=60)
339
+ ... async def some_fn():
340
+ ... return True
341
+ ...
342
+ >>> some_fn(sync=True)
343
+ True
217
344
 
218
345
  4. Applied directly to a function:
219
- ```python
220
- >>> some_fn = a_sync(some_existing_function, default='sync')
221
- >>> some_fn()
222
- "some return value"
223
- ```
346
+ >>> some_fn = a_sync(some_existing_function, default='sync')
347
+ >>> some_fn()
348
+ "some return value"
224
349
 
225
350
  The decorated function can then be called either synchronously or asynchronously:
226
351
 
227
- ```python
228
- result = some_fn() # Synchronous call
229
- result = await some_fn() # Asynchronous call
230
- ```
352
+ result = some_fn() # Synchronous call
353
+ result = await some_fn() # Asynchronous call
231
354
 
232
355
  The execution mode can also be explicitly specified during the call:
233
356
 
234
- ```python
235
- result = some_fn(sync=True) # Force synchronous execution
236
- result = await some_fn(sync=False) # Force asynchronous execution
237
- ```
357
+ result = some_fn(sync=True) # Force synchronous execution
358
+ result = await some_fn(sync=False) # Force asynchronous execution
238
359
 
239
360
  This decorator is particularly useful for libraries that need to support
240
361
  both synchronous and asynchronous usage, or for gradually migrating
241
362
  synchronous code to asynchronous without breaking existing interfaces.
242
363
  """
243
-
364
+
244
365
  # If the dev tried passing a default as an arg instead of a kwarg, ie: @a_sync('sync')...
245
- if coro_fn in ['async', 'sync']:
366
+ if coro_fn in ["async", "sync"]:
246
367
  default = coro_fn # type: ignore [assignment]
247
368
  coro_fn = None
248
-
369
+
249
370
  if default == "sync":
250
371
  deco = ASyncDecoratorSyncDefault(default=default, **modifiers)
251
372
  elif default == "async":
@@ -254,4 +375,5 @@ def a_sync(
254
375
  deco = ASyncDecorator(default=default, **modifiers)
255
376
  return deco if coro_fn is None else deco(coro_fn) # type: ignore [arg-type]
256
377
 
257
- # TODO: in a future release, I will make this usable with sync functions as well
378
+
379
+ # TODO: in a future release, I will make this usable with sync functions as well