ez-a-sync 0.22.15__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.
- a_sync/ENVIRONMENT_VARIABLES.py +34 -3
- a_sync/__init__.py +32 -9
- a_sync/_smart.py +105 -6
- a_sync/_typing.py +56 -3
- a_sync/a_sync/_descriptor.py +174 -12
- a_sync/a_sync/_flags.py +64 -3
- a_sync/a_sync/_helpers.py +40 -8
- a_sync/a_sync/_kwargs.py +30 -6
- a_sync/a_sync/_meta.py +35 -6
- a_sync/a_sync/abstract.py +57 -9
- a_sync/a_sync/config.py +44 -7
- a_sync/a_sync/decorator.py +217 -37
- a_sync/a_sync/function.py +339 -47
- a_sync/a_sync/method.py +241 -52
- a_sync/a_sync/modifiers/__init__.py +39 -1
- a_sync/a_sync/modifiers/cache/__init__.py +75 -5
- a_sync/a_sync/modifiers/cache/memory.py +50 -6
- a_sync/a_sync/modifiers/limiter.py +55 -6
- a_sync/a_sync/modifiers/manager.py +46 -2
- a_sync/a_sync/modifiers/semaphores.py +84 -11
- a_sync/a_sync/singleton.py +43 -19
- a_sync/asyncio/__init__.py +137 -1
- a_sync/asyncio/as_completed.py +44 -38
- a_sync/asyncio/create_task.py +46 -10
- a_sync/asyncio/gather.py +72 -25
- a_sync/exceptions.py +178 -11
- a_sync/executor.py +51 -3
- a_sync/future.py +671 -29
- a_sync/iter.py +64 -7
- a_sync/primitives/_debug.py +59 -5
- a_sync/primitives/_loggable.py +36 -6
- a_sync/primitives/locks/counter.py +74 -7
- a_sync/primitives/locks/prio_semaphore.py +87 -8
- a_sync/primitives/locks/semaphore.py +68 -20
- a_sync/primitives/queue.py +65 -26
- a_sync/task.py +51 -15
- a_sync/utils/iterators.py +52 -16
- {ez_a_sync-0.22.15.dist-info → ez_a_sync-0.22.16.dist-info}/METADATA +1 -1
- ez_a_sync-0.22.16.dist-info/RECORD +74 -0
- {ez_a_sync-0.22.15.dist-info → ez_a_sync-0.22.16.dist-info}/WHEEL +1 -1
- tests/executor.py +150 -12
- tests/test_abstract.py +15 -0
- tests/test_base.py +198 -2
- tests/test_executor.py +23 -0
- tests/test_singleton.py +13 -1
- tests/test_task.py +45 -17
- ez_a_sync-0.22.15.dist-info/RECORD +0 -74
- {ez_a_sync-0.22.15.dist-info → ez_a_sync-0.22.16.dist-info}/LICENSE.txt +0 -0
- {ez_a_sync-0.22.15.dist-info → ez_a_sync-0.22.16.dist-info}/top_level.txt +0 -0
a_sync/a_sync/method.py
CHANGED
|
@@ -31,8 +31,34 @@ logger = logging.getLogger(__name__)
|
|
|
31
31
|
|
|
32
32
|
class ASyncMethodDescriptor(ASyncDescriptor[I, P, T]):
|
|
33
33
|
"""
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
A descriptor for managing methods that can be called both synchronously and asynchronously.
|
|
35
|
+
|
|
36
|
+
This class provides the core functionality for binding methods to instances and determining
|
|
37
|
+
the execution mode ("sync" or "async") based on various conditions, such as the instance type,
|
|
38
|
+
the method's default setting, or specific flags passed during the method call.
|
|
39
|
+
|
|
40
|
+
The descriptor is responsible for creating an appropriate bound method when accessed,
|
|
41
|
+
which is the actual object that can be called in both synchronous and asynchronous contexts.
|
|
42
|
+
It can create different types of bound methods (`ASyncBoundMethodSyncDefault`,
|
|
43
|
+
`ASyncBoundMethodAsyncDefault`, or `ASyncBoundMethod`) based on the default mode or instance type.
|
|
44
|
+
|
|
45
|
+
It also manages cache handles for bound methods and prevents setting or deleting the descriptor.
|
|
46
|
+
|
|
47
|
+
Examples:
|
|
48
|
+
>>> class MyClass:
|
|
49
|
+
... @ASyncMethodDescriptor
|
|
50
|
+
... async def my_method(self):
|
|
51
|
+
... return "Hello, World!"
|
|
52
|
+
...
|
|
53
|
+
>>> obj = MyClass()
|
|
54
|
+
>>> await obj.my_method()
|
|
55
|
+
'Hello, World!'
|
|
56
|
+
>>> obj.my_method(sync=True)
|
|
57
|
+
'Hello, World!'
|
|
58
|
+
|
|
59
|
+
See Also:
|
|
60
|
+
- :class:`ASyncBoundMethod`
|
|
61
|
+
- :class:`ASyncFunction`
|
|
36
62
|
"""
|
|
37
63
|
|
|
38
64
|
__wrapped__: AnyFn[P, T]
|
|
@@ -47,8 +73,9 @@ class ASyncMethodDescriptor(ASyncDescriptor[I, P, T]):
|
|
|
47
73
|
*args: Positional arguments.
|
|
48
74
|
**kwargs: Keyword arguments.
|
|
49
75
|
|
|
50
|
-
|
|
51
|
-
|
|
76
|
+
Examples:
|
|
77
|
+
>>> descriptor = ASyncMethodDescriptor(my_async_function)
|
|
78
|
+
>>> await descriptor(instance, arg1, arg2, kwarg1=value1)
|
|
52
79
|
"""
|
|
53
80
|
# NOTE: This is only used by TaskMapping atm # TODO: use it elsewhere
|
|
54
81
|
logger.debug(
|
|
@@ -74,8 +101,9 @@ class ASyncMethodDescriptor(ASyncDescriptor[I, P, T]):
|
|
|
74
101
|
instance: The instance to bind the method to, or None.
|
|
75
102
|
owner: The owner class.
|
|
76
103
|
|
|
77
|
-
|
|
78
|
-
|
|
104
|
+
Examples:
|
|
105
|
+
>>> descriptor = ASyncMethodDescriptor(my_function)
|
|
106
|
+
>>> bound_method = descriptor.__get__(instance, MyClass)
|
|
79
107
|
"""
|
|
80
108
|
if instance is None:
|
|
81
109
|
return self
|
|
@@ -136,7 +164,12 @@ class ASyncMethodDescriptor(ASyncDescriptor[I, P, T]):
|
|
|
136
164
|
value: The value to set.
|
|
137
165
|
|
|
138
166
|
Raises:
|
|
139
|
-
:
|
|
167
|
+
RuntimeError: Always raised to prevent setting.
|
|
168
|
+
|
|
169
|
+
Examples:
|
|
170
|
+
>>> descriptor = ASyncMethodDescriptor(my_function)
|
|
171
|
+
>>> descriptor.__set__(instance, value)
|
|
172
|
+
RuntimeError: cannot set field_name, descriptor is what you get. sorry.
|
|
140
173
|
"""
|
|
141
174
|
raise RuntimeError(
|
|
142
175
|
f"cannot set {self.field_name}, {self} is what you get. sorry."
|
|
@@ -150,7 +183,12 @@ class ASyncMethodDescriptor(ASyncDescriptor[I, P, T]):
|
|
|
150
183
|
instance: The instance.
|
|
151
184
|
|
|
152
185
|
Raises:
|
|
153
|
-
:
|
|
186
|
+
RuntimeError: Always raised to prevent deletion.
|
|
187
|
+
|
|
188
|
+
Examples:
|
|
189
|
+
>>> descriptor = ASyncMethodDescriptor(my_function)
|
|
190
|
+
>>> descriptor.__delete__(instance)
|
|
191
|
+
RuntimeError: cannot delete field_name, you're stuck with descriptor forever. sorry.
|
|
154
192
|
"""
|
|
155
193
|
raise RuntimeError(
|
|
156
194
|
f"cannot delete {self.field_name}, you're stuck with {self} forever. sorry."
|
|
@@ -161,8 +199,10 @@ class ASyncMethodDescriptor(ASyncDescriptor[I, P, T]):
|
|
|
161
199
|
"""
|
|
162
200
|
Check if the wrapped function is a coroutine function.
|
|
163
201
|
|
|
164
|
-
|
|
165
|
-
|
|
202
|
+
Examples:
|
|
203
|
+
>>> descriptor = ASyncMethodDescriptor(my_function)
|
|
204
|
+
>>> descriptor.__is_async_def__
|
|
205
|
+
True
|
|
166
206
|
"""
|
|
167
207
|
return asyncio.iscoroutinefunction(self.__wrapped__)
|
|
168
208
|
|
|
@@ -175,6 +215,10 @@ class ASyncMethodDescriptor(ASyncDescriptor[I, P, T]):
|
|
|
175
215
|
|
|
176
216
|
Returns:
|
|
177
217
|
A timer handle for cache management.
|
|
218
|
+
|
|
219
|
+
Examples:
|
|
220
|
+
>>> descriptor = ASyncMethodDescriptor(my_function)
|
|
221
|
+
>>> cache_handle = descriptor._get_cache_handle(instance)
|
|
178
222
|
"""
|
|
179
223
|
# NOTE: use `instance.__dict__.pop` instead of `delattr` so we don't create a strong ref to `instance`
|
|
180
224
|
return asyncio.get_event_loop().call_later(
|
|
@@ -187,8 +231,28 @@ class ASyncMethodDescriptorSyncDefault(ASyncMethodDescriptor[I, P, T]):
|
|
|
187
231
|
"""
|
|
188
232
|
A descriptor for :class:`ASyncBoundMethodSyncDefault` objects.
|
|
189
233
|
|
|
190
|
-
This class extends ASyncMethodDescriptor to provide a synchronous
|
|
191
|
-
default behavior for method calls.
|
|
234
|
+
This class extends :class:`ASyncMethodDescriptor` to provide a synchronous
|
|
235
|
+
default behavior for method calls. It specifically creates `ASyncBoundMethodSyncDefault`
|
|
236
|
+
instances, which are specialized versions of `ASyncBoundMethod` with synchronous default behavior.
|
|
237
|
+
|
|
238
|
+
Examples:
|
|
239
|
+
>>> class MyClass:
|
|
240
|
+
... @ASyncMethodDescriptorSyncDefault
|
|
241
|
+
... def my_method(self):
|
|
242
|
+
... return "Hello, World!"
|
|
243
|
+
...
|
|
244
|
+
>>> obj = MyClass()
|
|
245
|
+
>>> obj.my_method()
|
|
246
|
+
'Hello, World!'
|
|
247
|
+
>>> coro = obj.my_method(sync=False)
|
|
248
|
+
>>> coro
|
|
249
|
+
<coroutine object MyClass.my_method at 0x7fb4f5fb49c0>
|
|
250
|
+
>>> await coro
|
|
251
|
+
'Hello, World!'
|
|
252
|
+
|
|
253
|
+
See Also:
|
|
254
|
+
- :class:`ASyncBoundMethodSyncDefault`
|
|
255
|
+
- :class:`ASyncFunctionSyncDefault`
|
|
192
256
|
"""
|
|
193
257
|
|
|
194
258
|
default = "sync"
|
|
@@ -229,8 +293,9 @@ class ASyncMethodDescriptorSyncDefault(ASyncMethodDescriptor[I, P, T]):
|
|
|
229
293
|
instance: The instance to bind the method to, or None.
|
|
230
294
|
owner: The owner class.
|
|
231
295
|
|
|
232
|
-
|
|
233
|
-
|
|
296
|
+
Examples:
|
|
297
|
+
>>> descriptor = ASyncMethodDescriptorSyncDefault(my_function)
|
|
298
|
+
>>> bound_method = descriptor.__get__(instance, MyClass)
|
|
234
299
|
"""
|
|
235
300
|
if instance is None:
|
|
236
301
|
return self
|
|
@@ -254,8 +319,27 @@ class ASyncMethodDescriptorAsyncDefault(ASyncMethodDescriptor[I, P, T]):
|
|
|
254
319
|
"""
|
|
255
320
|
A descriptor for asynchronous methods with an asynchronous default.
|
|
256
321
|
|
|
257
|
-
This class extends ASyncMethodDescriptor to provide an asynchronous default
|
|
258
|
-
behavior for method calls.
|
|
322
|
+
This class extends :class:`ASyncMethodDescriptor` to provide an asynchronous default
|
|
323
|
+
behavior for method calls. It specifically creates `ASyncBoundMethodAsyncDefault`
|
|
324
|
+
instances, which are specialized versions of `ASyncBoundMethod` with asynchronous default behavior.
|
|
325
|
+
|
|
326
|
+
Examples:
|
|
327
|
+
>>> class MyClass:
|
|
328
|
+
... @ASyncMethodDescriptorAsyncDefault
|
|
329
|
+
... async def my_method(self):
|
|
330
|
+
... return "Hello, World!"
|
|
331
|
+
...
|
|
332
|
+
>>> obj = MyClass()
|
|
333
|
+
>>> coro = obj.my_method()
|
|
334
|
+
>>> coro
|
|
335
|
+
<coroutine object MyClass.my_method at 0x7fb4f5fb49c0>
|
|
336
|
+
>>> await coro
|
|
337
|
+
>>> obj.my_method(sync=True)
|
|
338
|
+
'Hello, World!'
|
|
339
|
+
|
|
340
|
+
See Also:
|
|
341
|
+
- :class:`ASyncBoundMethodAsyncDefault`
|
|
342
|
+
- :class:`ASyncFunctionAsyncDefault`
|
|
259
343
|
"""
|
|
260
344
|
|
|
261
345
|
default = "async"
|
|
@@ -294,8 +378,9 @@ class ASyncMethodDescriptorAsyncDefault(ASyncMethodDescriptor[I, P, T]):
|
|
|
294
378
|
instance: The instance to bind the method to, or None.
|
|
295
379
|
owner: The owner class.
|
|
296
380
|
|
|
297
|
-
|
|
298
|
-
|
|
381
|
+
Examples:
|
|
382
|
+
>>> descriptor = ASyncMethodDescriptorAsyncDefault(my_function)
|
|
383
|
+
>>> bound_method = descriptor.__get__(instance, MyClass)
|
|
299
384
|
"""
|
|
300
385
|
if instance is None:
|
|
301
386
|
return self
|
|
@@ -319,16 +404,37 @@ class ASyncBoundMethod(ASyncFunction[P, T], Generic[I, P, T]):
|
|
|
319
404
|
A bound method that can be called both synchronously and asynchronously.
|
|
320
405
|
|
|
321
406
|
This class represents a method bound to an instance, which can be called
|
|
322
|
-
either synchronously or asynchronously based on various conditions.
|
|
407
|
+
either synchronously or asynchronously based on various conditions. It handles
|
|
408
|
+
caching of bound methods and includes logic for determining whether to await
|
|
409
|
+
the method call based on flags or default settings.
|
|
410
|
+
|
|
411
|
+
Examples:
|
|
412
|
+
>>> class MyClass:
|
|
413
|
+
... def __init__(self, value):
|
|
414
|
+
... self.value = value
|
|
415
|
+
...
|
|
416
|
+
... @ASyncMethodDescriptor
|
|
417
|
+
... async def my_method(self):
|
|
418
|
+
... return self.value
|
|
419
|
+
...
|
|
420
|
+
>>> obj = MyClass(42)
|
|
421
|
+
>>> await obj.my_method()
|
|
422
|
+
42
|
|
423
|
+
>>> obj.my_method(sync=True)
|
|
424
|
+
42
|
|
425
|
+
|
|
426
|
+
See Also:
|
|
427
|
+
- :class:`ASyncMethodDescriptor`
|
|
428
|
+
- :class:`ASyncFunction`
|
|
323
429
|
"""
|
|
324
430
|
|
|
325
431
|
# NOTE: this is created by the Descriptor
|
|
326
432
|
|
|
327
433
|
_cache_handle: asyncio.TimerHandle
|
|
328
|
-
"An asyncio handle used to pop the bound method from `instance.__dict__` 5 minutes after its last use."
|
|
434
|
+
"""An asyncio handle used to pop the bound method from `instance.__dict__` 5 minutes after its last use."""
|
|
329
435
|
|
|
330
436
|
__weakself__: "weakref.ref[I]"
|
|
331
|
-
"A weak reference to the instance the function is bound to."
|
|
437
|
+
"""A weak reference to the instance the function is bound to."""
|
|
332
438
|
|
|
333
439
|
__wrapped__: AnyFn[Concatenate[I, P], T]
|
|
334
440
|
"""The original unbound method that was wrapped."""
|
|
@@ -350,6 +456,18 @@ class ASyncBoundMethod(ASyncFunction[P, T], Generic[I, P, T]):
|
|
|
350
456
|
unbound: The unbound function.
|
|
351
457
|
async_def: Whether the original function is an async def.
|
|
352
458
|
**modifiers: Additional modifiers for the function.
|
|
459
|
+
|
|
460
|
+
Examples:
|
|
461
|
+
>>> class MyClass:
|
|
462
|
+
... def __init__(self, value):
|
|
463
|
+
... self.value = value
|
|
464
|
+
...
|
|
465
|
+
... @ASyncMethodDescriptor
|
|
466
|
+
... async def my_method(self):
|
|
467
|
+
... return self.value
|
|
468
|
+
...
|
|
469
|
+
>>> obj = MyClass(42)
|
|
470
|
+
>>> bound_method = ASyncBoundMethod(obj, MyClass.my_method, True)
|
|
353
471
|
"""
|
|
354
472
|
self.__weakself__ = weakref.ref(instance, self.__cancel_cache_handle)
|
|
355
473
|
# First we unwrap the coro_fn and rewrap it so overriding flag kwargs are handled automagically.
|
|
@@ -358,15 +476,17 @@ class ASyncBoundMethod(ASyncFunction[P, T], Generic[I, P, T]):
|
|
|
358
476
|
unbound = unbound.__wrapped__
|
|
359
477
|
ASyncFunction.__init__(self, unbound, **modifiers)
|
|
360
478
|
self._is_async_def = async_def
|
|
361
|
-
"True if `self.__wrapped__` is a coroutine function, False otherwise."
|
|
479
|
+
"""True if `self.__wrapped__` is a coroutine function, False otherwise."""
|
|
362
480
|
functools.update_wrapper(self, unbound)
|
|
363
481
|
|
|
364
482
|
def __repr__(self) -> str:
|
|
365
483
|
"""
|
|
366
484
|
Return a string representation of the bound method.
|
|
367
485
|
|
|
368
|
-
|
|
369
|
-
|
|
486
|
+
Examples:
|
|
487
|
+
>>> bound_method = ASyncBoundMethod(instance, my_function, True)
|
|
488
|
+
>>> repr(bound_method)
|
|
489
|
+
'<ASyncBoundMethod for function module.ClassName.method_name bound to instance>'
|
|
370
490
|
"""
|
|
371
491
|
try:
|
|
372
492
|
instance_type = type(self.__self__)
|
|
@@ -401,8 +521,10 @@ class ASyncBoundMethod(ASyncFunction[P, T], Generic[I, P, T]):
|
|
|
401
521
|
*args: Positional arguments.
|
|
402
522
|
**kwargs: Keyword arguments.
|
|
403
523
|
|
|
404
|
-
|
|
405
|
-
|
|
524
|
+
Examples:
|
|
525
|
+
>>> bound_method = ASyncBoundMethod(instance, my_function, True)
|
|
526
|
+
>>> await bound_method(arg1, arg2, kwarg1=value1)
|
|
527
|
+
>>> bound_method(arg1, arg2, kwarg1=value1, sync=True)
|
|
406
528
|
"""
|
|
407
529
|
logger.debug("calling %s with args: %s kwargs: %s", self, args, kwargs)
|
|
408
530
|
# This could either be a coroutine or a return value from an awaited coroutine,
|
|
@@ -428,11 +550,13 @@ class ASyncBoundMethod(ASyncFunction[P, T], Generic[I, P, T]):
|
|
|
428
550
|
"""
|
|
429
551
|
Get the instance the method is bound to.
|
|
430
552
|
|
|
431
|
-
Returns:
|
|
432
|
-
The instance the method is bound to.
|
|
433
|
-
|
|
434
553
|
Raises:
|
|
435
|
-
:
|
|
554
|
+
ReferenceError: If the instance has been garbage collected.
|
|
555
|
+
|
|
556
|
+
Examples:
|
|
557
|
+
>>> bound_method = ASyncBoundMethod(instance, my_function, True)
|
|
558
|
+
>>> bound_method.__self__
|
|
559
|
+
<MyClass instance>
|
|
436
560
|
"""
|
|
437
561
|
instance = self.__weakself__()
|
|
438
562
|
if instance is not None:
|
|
@@ -444,8 +568,10 @@ class ASyncBoundMethod(ASyncFunction[P, T], Generic[I, P, T]):
|
|
|
444
568
|
"""
|
|
445
569
|
Check if the method is bound to an ASyncABC instance.
|
|
446
570
|
|
|
447
|
-
|
|
448
|
-
|
|
571
|
+
Examples:
|
|
572
|
+
>>> bound_method = ASyncBoundMethod(instance, my_function, True)
|
|
573
|
+
>>> bound_method.__bound_to_a_sync_instance__
|
|
574
|
+
True
|
|
449
575
|
"""
|
|
450
576
|
from a_sync.a_sync.abstract import ASyncABC
|
|
451
577
|
|
|
@@ -469,6 +595,11 @@ class ASyncBoundMethod(ASyncFunction[P, T], Generic[I, P, T]):
|
|
|
469
595
|
|
|
470
596
|
Returns:
|
|
471
597
|
A TaskMapping instance for this method.
|
|
598
|
+
|
|
599
|
+
Examples:
|
|
600
|
+
>>> bound_method = ASyncBoundMethod(instance, my_function, True)
|
|
601
|
+
>>> task_mapping = bound_method.map(iterable1, iterable2, concurrency=5)
|
|
602
|
+
TODO briefly include how someone would then use task_mapping
|
|
472
603
|
"""
|
|
473
604
|
from a_sync import TaskMapping
|
|
474
605
|
|
|
@@ -492,8 +623,9 @@ class ASyncBoundMethod(ASyncFunction[P, T], Generic[I, P, T]):
|
|
|
492
623
|
task_name: Optional name for the task.
|
|
493
624
|
**kwargs: Additional keyword arguments.
|
|
494
625
|
|
|
495
|
-
|
|
496
|
-
|
|
626
|
+
Examples:
|
|
627
|
+
>>> bound_method = ASyncBoundMethod(instance, my_function, True)
|
|
628
|
+
>>> result = await bound_method.any(iterable1, iterable2)
|
|
497
629
|
"""
|
|
498
630
|
return await self.map(
|
|
499
631
|
*iterables, concurrency=concurrency, task_name=task_name, **kwargs
|
|
@@ -515,8 +647,9 @@ class ASyncBoundMethod(ASyncFunction[P, T], Generic[I, P, T]):
|
|
|
515
647
|
task_name: Optional name for the task.
|
|
516
648
|
**kwargs: Additional keyword arguments.
|
|
517
649
|
|
|
518
|
-
|
|
519
|
-
|
|
650
|
+
Examples:
|
|
651
|
+
>>> bound_method = ASyncBoundMethod(instance, my_function, True)
|
|
652
|
+
>>> result = await bound_method.all(iterable1, iterable2)
|
|
520
653
|
"""
|
|
521
654
|
return await self.map(
|
|
522
655
|
*iterables, concurrency=concurrency, task_name=task_name, **kwargs
|
|
@@ -538,8 +671,9 @@ class ASyncBoundMethod(ASyncFunction[P, T], Generic[I, P, T]):
|
|
|
538
671
|
task_name: Optional name for the task.
|
|
539
672
|
**kwargs: Additional keyword arguments.
|
|
540
673
|
|
|
541
|
-
|
|
542
|
-
|
|
674
|
+
Examples:
|
|
675
|
+
>>> bound_method = ASyncBoundMethod(instance, my_function, True)
|
|
676
|
+
>>> result = await bound_method.min(iterable1, iterable2)
|
|
543
677
|
"""
|
|
544
678
|
return await self.map(
|
|
545
679
|
*iterables, concurrency=concurrency, task_name=task_name, **kwargs
|
|
@@ -561,8 +695,9 @@ class ASyncBoundMethod(ASyncFunction[P, T], Generic[I, P, T]):
|
|
|
561
695
|
task_name: Optional name for the task.
|
|
562
696
|
**kwargs: Additional keyword arguments.
|
|
563
697
|
|
|
564
|
-
|
|
565
|
-
|
|
698
|
+
Examples:
|
|
699
|
+
>>> bound_method = ASyncBoundMethod(instance, my_function, True)
|
|
700
|
+
>>> result = await bound_method.max(iterable1, iterable2)
|
|
566
701
|
"""
|
|
567
702
|
return await self.map(
|
|
568
703
|
*iterables, concurrency=concurrency, task_name=task_name, **kwargs
|
|
@@ -584,8 +719,9 @@ class ASyncBoundMethod(ASyncFunction[P, T], Generic[I, P, T]):
|
|
|
584
719
|
task_name: Optional name for the task.
|
|
585
720
|
**kwargs: Additional keyword arguments.
|
|
586
721
|
|
|
587
|
-
|
|
588
|
-
|
|
722
|
+
Examples:
|
|
723
|
+
>>> bound_method = ASyncBoundMethod(instance, my_function, True)
|
|
724
|
+
>>> result = await bound_method.sum(iterable1, iterable2)
|
|
589
725
|
"""
|
|
590
726
|
return await self.map(
|
|
591
727
|
*iterables, concurrency=concurrency, task_name=task_name, **kwargs
|
|
@@ -598,8 +734,9 @@ class ASyncBoundMethod(ASyncFunction[P, T], Generic[I, P, T]):
|
|
|
598
734
|
Args:
|
|
599
735
|
kwargs: Keyword arguments passed to the method.
|
|
600
736
|
|
|
601
|
-
|
|
602
|
-
|
|
737
|
+
Examples:
|
|
738
|
+
>>> bound_method = ASyncBoundMethod(instance, my_function, True)
|
|
739
|
+
>>> should_await = bound_method._should_await(kwargs)
|
|
603
740
|
"""
|
|
604
741
|
if flag := _kwargs.get_flag_name(kwargs):
|
|
605
742
|
return _kwargs.is_sync(flag, kwargs, pop_flag=True) # type: ignore [arg-type]
|
|
@@ -616,6 +753,10 @@ class ASyncBoundMethod(ASyncFunction[P, T], Generic[I, P, T]):
|
|
|
616
753
|
|
|
617
754
|
Args:
|
|
618
755
|
instance: The instance associated with the cache handle.
|
|
756
|
+
|
|
757
|
+
Examples:
|
|
758
|
+
>>> bound_method = ASyncBoundMethod(instance, my_function, True)
|
|
759
|
+
>>> bound_method.__cancel_cache_handle(instance)
|
|
619
760
|
"""
|
|
620
761
|
cache_handle: asyncio.TimerHandle = self._cache_handle
|
|
621
762
|
cache_handle.cancel()
|
|
@@ -624,6 +765,28 @@ class ASyncBoundMethod(ASyncFunction[P, T], Generic[I, P, T]):
|
|
|
624
765
|
class ASyncBoundMethodSyncDefault(ASyncBoundMethod[I, P, T]):
|
|
625
766
|
"""
|
|
626
767
|
A bound method with synchronous default behavior.
|
|
768
|
+
|
|
769
|
+
This class is a specialized version of :class:`ASyncBoundMethod` that defaults to synchronous execution.
|
|
770
|
+
It overrides the `__call__` method to enforce synchronous default behavior.
|
|
771
|
+
|
|
772
|
+
Examples:
|
|
773
|
+
>>> class MyClass:
|
|
774
|
+
... def __init__(self, value):
|
|
775
|
+
... self.value = value
|
|
776
|
+
...
|
|
777
|
+
... @ASyncMethodDescriptorSyncDefault
|
|
778
|
+
... def my_method(self):
|
|
779
|
+
... return self.value
|
|
780
|
+
...
|
|
781
|
+
>>> obj = MyClass(42)
|
|
782
|
+
>>> obj.my_method()
|
|
783
|
+
42
|
|
784
|
+
>>> await obj.my_method(sync=False)
|
|
785
|
+
42
|
|
786
|
+
|
|
787
|
+
See Also:
|
|
788
|
+
- :class:`ASyncBoundMethod`
|
|
789
|
+
- :class:`ASyncMethodDescriptorSyncDefault`
|
|
627
790
|
"""
|
|
628
791
|
|
|
629
792
|
def __get__(
|
|
@@ -636,8 +799,9 @@ class ASyncBoundMethodSyncDefault(ASyncBoundMethod[I, P, T]):
|
|
|
636
799
|
instance: The instance to bind the method to, or None.
|
|
637
800
|
owner: The owner class.
|
|
638
801
|
|
|
639
|
-
|
|
640
|
-
|
|
802
|
+
Examples:
|
|
803
|
+
>>> descriptor = ASyncMethodDescriptorSyncDefault(my_function)
|
|
804
|
+
>>> bound_method = descriptor.__get__(instance, MyClass)
|
|
641
805
|
"""
|
|
642
806
|
return ASyncBoundMethod.__get__(self, instance, owner)
|
|
643
807
|
|
|
@@ -665,8 +829,9 @@ class ASyncBoundMethodSyncDefault(ASyncBoundMethod[I, P, T]):
|
|
|
665
829
|
*args: Positional arguments.
|
|
666
830
|
**kwargs: Keyword arguments.
|
|
667
831
|
|
|
668
|
-
|
|
669
|
-
|
|
832
|
+
Examples:
|
|
833
|
+
>>> bound_method = ASyncBoundMethodSyncDefault(instance, my_function, True)
|
|
834
|
+
>>> bound_method(arg1, arg2, kwarg1=value1)
|
|
670
835
|
"""
|
|
671
836
|
return ASyncBoundMethod.__call__(self, *args, **kwargs)
|
|
672
837
|
|
|
@@ -674,6 +839,28 @@ class ASyncBoundMethodSyncDefault(ASyncBoundMethod[I, P, T]):
|
|
|
674
839
|
class ASyncBoundMethodAsyncDefault(ASyncBoundMethod[I, P, T]):
|
|
675
840
|
"""
|
|
676
841
|
A bound method with asynchronous default behavior.
|
|
842
|
+
|
|
843
|
+
This class is a specialized version of :class:`ASyncBoundMethod` that defaults to asynchronous execution.
|
|
844
|
+
It overrides the `__call__` method to enforce asynchronous default behavior.
|
|
845
|
+
|
|
846
|
+
Examples:
|
|
847
|
+
>>> class MyClass:
|
|
848
|
+
... def __init__(self, value):
|
|
849
|
+
... self.value = value
|
|
850
|
+
...
|
|
851
|
+
... @ASyncMethodDescriptorAsyncDefault
|
|
852
|
+
... async def my_method(self):
|
|
853
|
+
... return self.value
|
|
854
|
+
...
|
|
855
|
+
>>> obj = MyClass(42)
|
|
856
|
+
>>> await obj.my_method()
|
|
857
|
+
42
|
|
858
|
+
>>> obj.my_method(sync=True)
|
|
859
|
+
42
|
|
860
|
+
|
|
861
|
+
See Also:
|
|
862
|
+
- :class:`ASyncBoundMethod`
|
|
863
|
+
- :class:`ASyncMethodDescriptorAsyncDefault`
|
|
677
864
|
"""
|
|
678
865
|
|
|
679
866
|
def __get__(self, instance: I, owner: Type[I]) -> ASyncFunctionAsyncDefault[P, T]:
|
|
@@ -684,8 +871,9 @@ class ASyncBoundMethodAsyncDefault(ASyncBoundMethod[I, P, T]):
|
|
|
684
871
|
instance: The instance to bind the method to.
|
|
685
872
|
owner: The owner class.
|
|
686
873
|
|
|
687
|
-
|
|
688
|
-
|
|
874
|
+
Examples:
|
|
875
|
+
>>> descriptor = ASyncMethodDescriptorAsyncDefault(my_function)
|
|
876
|
+
>>> bound_method = descriptor.__get__(instance, MyClass)
|
|
689
877
|
"""
|
|
690
878
|
return ASyncBoundMethod.__get__(self, instance, owner)
|
|
691
879
|
|
|
@@ -713,7 +901,8 @@ class ASyncBoundMethodAsyncDefault(ASyncBoundMethod[I, P, T]):
|
|
|
713
901
|
*args: Positional arguments.
|
|
714
902
|
**kwargs: Keyword arguments.
|
|
715
903
|
|
|
716
|
-
|
|
717
|
-
|
|
904
|
+
Examples:
|
|
905
|
+
>>> bound_method = ASyncBoundMethodAsyncDefault(instance, my_function, True)
|
|
906
|
+
>>> await bound_method(arg1, arg2, kwarg1=value1)
|
|
718
907
|
"""
|
|
719
908
|
return ASyncBoundMethod.__call__(self, *args, **kwargs)
|
|
@@ -16,8 +16,13 @@ The modifiers available are:
|
|
|
16
16
|
- `ram_cache_ttl`: Defines the time-to-live for items in the cache.
|
|
17
17
|
- `runs_per_minute`: Sets a rate limit for function execution.
|
|
18
18
|
- `semaphore`: Specifies a semaphore for controlling concurrency.
|
|
19
|
-
- `executor`: Defines the executor for synchronous functions.
|
|
19
|
+
- `executor`: Defines the executor for synchronous functions. This is not applied like the other modifiers but is used to manage the execution context for synchronous functions when they are called in an asynchronous manner.
|
|
20
20
|
|
|
21
|
+
See Also:
|
|
22
|
+
- :mod:`a_sync.a_sync.modifiers.cache`
|
|
23
|
+
- :mod:`a_sync.a_sync.modifiers.limiter`
|
|
24
|
+
- :mod:`a_sync.a_sync.modifiers.manager`
|
|
25
|
+
- :mod:`a_sync.a_sync.modifiers.semaphores`
|
|
21
26
|
"""
|
|
22
27
|
|
|
23
28
|
from aiolimiter import AsyncLimiter
|
|
@@ -36,6 +41,24 @@ def get_modifiers_from(thing: Union[dict, type, object]) -> ModifierKwargs:
|
|
|
36
41
|
|
|
37
42
|
Returns:
|
|
38
43
|
A ModifierKwargs object containing the valid modifiers extracted from the input.
|
|
44
|
+
|
|
45
|
+
Examples:
|
|
46
|
+
Extracting modifiers from a class:
|
|
47
|
+
|
|
48
|
+
>>> class Example:
|
|
49
|
+
... cache_type = 'memory'
|
|
50
|
+
... runs_per_minute = 60
|
|
51
|
+
>>> get_modifiers_from(Example)
|
|
52
|
+
ModifierKwargs({'cache_type': 'memory', 'runs_per_minute': 60})
|
|
53
|
+
|
|
54
|
+
Extracting modifiers from a dictionary:
|
|
55
|
+
|
|
56
|
+
>>> modifiers_dict = {'cache_type': 'memory', 'semaphore': 5}
|
|
57
|
+
>>> get_modifiers_from(modifiers_dict)
|
|
58
|
+
ModifierKwargs({'cache_type': 'memory', 'semaphore': ThreadsafeSemaphore(5)})
|
|
59
|
+
|
|
60
|
+
See Also:
|
|
61
|
+
- :class:`a_sync.a_sync.modifiers.manager.ModifierManager`
|
|
39
62
|
"""
|
|
40
63
|
if isinstance(thing, dict):
|
|
41
64
|
apply_class_defined_modifiers(thing)
|
|
@@ -54,6 +77,21 @@ def apply_class_defined_modifiers(attrs_from_metaclass: dict):
|
|
|
54
77
|
|
|
55
78
|
Args:
|
|
56
79
|
attrs_from_metaclass: A dictionary of attributes from a metaclass.
|
|
80
|
+
|
|
81
|
+
Examples:
|
|
82
|
+
Applying modifiers to a dictionary:
|
|
83
|
+
|
|
84
|
+
>>> attrs = {'semaphore': 3, 'runs_per_minute': 60}
|
|
85
|
+
>>> apply_class_defined_modifiers(attrs)
|
|
86
|
+
>>> attrs['semaphore']
|
|
87
|
+
ThreadsafeSemaphore(3)
|
|
88
|
+
|
|
89
|
+
>>> attrs['runs_per_minute']
|
|
90
|
+
AsyncLimiter(60)
|
|
91
|
+
|
|
92
|
+
See Also:
|
|
93
|
+
- :class:`a_sync.primitives.locks.ThreadsafeSemaphore`
|
|
94
|
+
- :class:`aiolimiter.AsyncLimiter`
|
|
57
95
|
"""
|
|
58
96
|
if isinstance(val := attrs_from_metaclass.get("semaphore"), int):
|
|
59
97
|
attrs_from_metaclass["semaphore"] = ThreadsafeSemaphore(val)
|