reykit 1.1.12__py3-none-any.whl → 1.1.13__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.
- reykit/rmultitask.py +537 -579
- reykit/rnumber.py +32 -9
- reykit/rtime.py +41 -2
- {reykit-1.1.12.dist-info → reykit-1.1.13.dist-info}/METADATA +1 -1
- {reykit-1.1.12.dist-info → reykit-1.1.13.dist-info}/RECORD +7 -7
- {reykit-1.1.12.dist-info → reykit-1.1.13.dist-info}/WHEEL +0 -0
- {reykit-1.1.12.dist-info → reykit-1.1.13.dist-info}/licenses/LICENSE +0 -0
reykit/rmultitask.py
CHANGED
@@ -10,363 +10,51 @@
|
|
10
10
|
|
11
11
|
|
12
12
|
from __future__ import annotations
|
13
|
-
from typing import Any, Literal,
|
14
|
-
from collections.abc import Callable, Iterable,
|
13
|
+
from typing import Any, Literal, overload
|
14
|
+
from collections.abc import Callable, Iterable, Generator, Coroutine
|
15
15
|
from threading import RLock as TRLock, get_ident as threading_get_ident
|
16
16
|
from concurrent.futures import ThreadPoolExecutor, Future as CFuture, as_completed as concurrent_as_completed
|
17
|
+
from queue import Queue as QQueue
|
17
18
|
from asyncio import (
|
18
19
|
Future as AFuture,
|
19
|
-
Queue as AQueue,
|
20
20
|
Lock as ALock,
|
21
|
+
Task as ATask,
|
22
|
+
Queue as AQueue,
|
23
|
+
sleep as asyncio_sleep,
|
21
24
|
run as asyncio_run,
|
22
25
|
gather as asyncio_gather,
|
23
|
-
iscoroutine
|
26
|
+
iscoroutine as asyncio_iscoroutine,
|
27
|
+
iscoroutinefunction as asyncio_iscoroutinefunction,
|
28
|
+
run_coroutine_threadsafe as asyncio_run_coroutine_threadsafe,
|
29
|
+
new_event_loop as asyncio_new_event_loop,
|
30
|
+
set_event_loop as asyncio_set_event_loop
|
24
31
|
)
|
25
|
-
from asyncio.queues import QueueEmpty
|
26
32
|
from aiohttp import ClientSession, ClientResponse
|
27
33
|
|
28
34
|
from .rexception import throw, check_most_one, check_response_code
|
29
|
-
from .rtime import
|
35
|
+
from .rtime import randn, RTimeMark
|
36
|
+
from .rtype import T
|
30
37
|
from .rwrap import wrap_thread
|
31
38
|
|
32
39
|
|
33
40
|
__all__ = (
|
41
|
+
'RThreadPool',
|
34
42
|
'async_run',
|
43
|
+
'async_sleep',
|
44
|
+
'async_wait',
|
35
45
|
'async_request',
|
36
|
-
'
|
37
|
-
'RAsyncLock',
|
38
|
-
'RThreadPool',
|
39
|
-
'RAsyncPool',
|
40
|
-
'RAsyncIterator'
|
46
|
+
'RAsyncPool'
|
41
47
|
)
|
42
48
|
|
43
49
|
|
44
|
-
def async_run(*coroutines: Coroutine) -> list:
|
45
|
-
"""
|
46
|
-
Asynchronous run `Coroutine` instances.
|
47
|
-
|
48
|
-
Parameters
|
49
|
-
----------
|
50
|
-
coroutines : `Coroutine` instances.
|
51
|
-
|
52
|
-
Returns
|
53
|
-
-------
|
54
|
-
Run result list.
|
55
|
-
"""
|
56
|
-
|
57
|
-
|
58
|
-
# Define.
|
59
|
-
async def gather_coroutine() -> AFuture:
|
60
|
-
"""
|
61
|
-
Get `Future` instance.
|
62
|
-
|
63
|
-
Returns
|
64
|
-
-------
|
65
|
-
Future instance.
|
66
|
-
"""
|
67
|
-
|
68
|
-
# Gather.
|
69
|
-
future = await asyncio_gather(*coroutines)
|
70
|
-
|
71
|
-
return future
|
72
|
-
|
73
|
-
|
74
|
-
# Run.
|
75
|
-
result = asyncio_run(gather_coroutine())
|
76
|
-
|
77
|
-
return result
|
78
|
-
|
79
|
-
|
80
|
-
async def async_request(
|
81
|
-
url: str,
|
82
|
-
params: dict | None = None,
|
83
|
-
data: dict | str | bytes | None = None,
|
84
|
-
json: dict | None = None,
|
85
|
-
headers: dict[str, str] = {},
|
86
|
-
timeout: float | None = None,
|
87
|
-
proxy: str | None = None,
|
88
|
-
method: Literal['get', 'post', 'put', 'patch', 'delete', 'options', 'head'] | None = None,
|
89
|
-
check: bool | int | Iterable[int] = False,
|
90
|
-
handler: str | tuple[str] | Callable[[ClientResponse], Coroutine | Any] | None = None
|
91
|
-
) -> Any:
|
92
|
-
"""
|
93
|
-
Get asynchronous `Coroutine` instance of send request.
|
94
|
-
|
95
|
-
Parameters
|
96
|
-
----------
|
97
|
-
url : Request URL.
|
98
|
-
params : Request URL add parameters.
|
99
|
-
data : Request body data. Conflict with parameter `json`.
|
100
|
-
- `dict`, Convert to `key=value&...`: format bytes.
|
101
|
-
Automatic set `Content-Type` to `application/x-www-form-urlencoded`.
|
102
|
-
- `dict and a certain value is 'bytes' type`: Key is parameter name and file name, value is file data.
|
103
|
-
Automatic set `Content-Type` to `multipart/form-data`.
|
104
|
-
- `str`: File path to read file bytes data.
|
105
|
-
Automatic set `Content-Type` to file media type, and `filename` to file name.
|
106
|
-
- `bytes`: File bytes data.
|
107
|
-
Automatic set `Content-Type` to file media type.
|
108
|
-
json : Request body data, convert to `JSON` format. Conflict with parameter `data`.
|
109
|
-
Automatic set `Content-Type` to `application/json`.
|
110
|
-
headers : Request header data.
|
111
|
-
timeout : Request maximun waiting time.
|
112
|
-
proxy : Proxy URL.
|
113
|
-
method : Request method.
|
114
|
-
- `None`: Automatic judge.
|
115
|
-
When parameter `data` or `json` not has value, then request method is `get`.
|
116
|
-
When parameter `data` or `json` has value, then request method is `post`.
|
117
|
-
- `Literal['get', 'post', 'put', 'patch', 'delete', 'options', 'head']`: Use this request method.
|
118
|
-
check : Check response code, and throw exception.
|
119
|
-
- `Literal[False]`: Not check.
|
120
|
-
- `Literal[True]`: Check if is between 200 and 299.
|
121
|
-
- `int`: Check if is this value.
|
122
|
-
- `Iterable`: Check if is in sequence.
|
123
|
-
handler : Response handler.
|
124
|
-
- `None`: Automatic handle.
|
125
|
-
`Response 'Content-Type' is 'application/json'`: Use `ClientResponse.json` method.
|
126
|
-
`Response 'Content-Type' is 'text/plain; charset=utf-8'`: Use `ClientResponse.text` method.
|
127
|
-
`Other`: Use `ClientResponse.read` method.
|
128
|
-
- `str`: Get this attribute.
|
129
|
-
`Callable`: Execute this method. When return `Coroutine`, then use `await` syntax execute `Coroutine`.
|
130
|
-
`Any`: Return this value.
|
131
|
-
- `tuple[str]`: Get these attribute.
|
132
|
-
`Callable`: Execute this method. When return `Coroutine`, then use `await` syntax execute `Coroutine`.
|
133
|
-
`Any`: Return this value.
|
134
|
-
- `Callable`, Execute this method. When return `Coroutine`, then use `await`: syntax execute `Coroutine`.
|
135
|
-
|
136
|
-
Returns
|
137
|
-
-------
|
138
|
-
Response handler result.
|
139
|
-
"""
|
140
|
-
|
141
|
-
# Check.
|
142
|
-
check_most_one(data, json)
|
143
|
-
|
144
|
-
# Handle parameter.
|
145
|
-
if method is None:
|
146
|
-
if data is None and json is None:
|
147
|
-
method = 'get'
|
148
|
-
else:
|
149
|
-
method = 'post'
|
150
|
-
|
151
|
-
# Session.
|
152
|
-
async with ClientSession() as session:
|
153
|
-
|
154
|
-
# Request.
|
155
|
-
async with session.request(
|
156
|
-
method,
|
157
|
-
url,
|
158
|
-
params=params,
|
159
|
-
data=data,
|
160
|
-
json=json,
|
161
|
-
headers=headers,
|
162
|
-
timeout=timeout,
|
163
|
-
proxy=proxy
|
164
|
-
) as response:
|
165
|
-
|
166
|
-
# Check code.
|
167
|
-
if check is not False:
|
168
|
-
if check is True:
|
169
|
-
range_ = None
|
170
|
-
else:
|
171
|
-
range_ = check
|
172
|
-
check_response_code(response.status, range_)
|
173
|
-
|
174
|
-
# Receive.
|
175
|
-
match handler:
|
176
|
-
|
177
|
-
## Auto.
|
178
|
-
case None:
|
179
|
-
match response.content_type:
|
180
|
-
case 'application/json':
|
181
|
-
result = await response.json()
|
182
|
-
case 'text/plain; charset=utf-8':
|
183
|
-
|
184
|
-
# Set encode type.
|
185
|
-
if response.get_encoding() == 'ISO-8859-1':
|
186
|
-
encoding = 'utf-8'
|
187
|
-
else:
|
188
|
-
encoding = None
|
189
|
-
|
190
|
-
result = await response.text(encoding=encoding)
|
191
|
-
case _:
|
192
|
-
result = await response.read()
|
193
|
-
|
194
|
-
## Attribute.
|
195
|
-
case str():
|
196
|
-
result = getattr(response, handler)
|
197
|
-
|
198
|
-
### Method.
|
199
|
-
if callable(result):
|
200
|
-
result = result()
|
201
|
-
|
202
|
-
#### Coroutine.
|
203
|
-
if iscoroutine(result):
|
204
|
-
result = await result
|
205
|
-
|
206
|
-
## Attributes.
|
207
|
-
case tuple():
|
208
|
-
result = []
|
209
|
-
for key in handler:
|
210
|
-
result_element = getattr(response, key)
|
211
|
-
|
212
|
-
### Method.
|
213
|
-
if callable(result_element):
|
214
|
-
result_element = result_element()
|
215
|
-
|
216
|
-
#### Coroutine.
|
217
|
-
if iscoroutine(result_element):
|
218
|
-
result_element = await result_element
|
219
|
-
|
220
|
-
result.append(result_element)
|
221
|
-
|
222
|
-
## Method.
|
223
|
-
case _ if callable(handler):
|
224
|
-
result = handler(response)
|
225
|
-
|
226
|
-
### Coroutine.
|
227
|
-
if iscoroutine(result):
|
228
|
-
result = await result
|
229
|
-
|
230
|
-
## Throw exception.
|
231
|
-
case _:
|
232
|
-
throw(TypeError, handler)
|
233
|
-
|
234
|
-
return result
|
235
|
-
|
236
|
-
|
237
|
-
class RThreadLock():
|
238
|
-
"""
|
239
|
-
Rey's `thread lock` type.
|
240
|
-
"""
|
241
|
-
|
242
|
-
|
243
|
-
def __init__(self) -> None:
|
244
|
-
"""
|
245
|
-
Build `thread lock` attributes.
|
246
|
-
"""
|
247
|
-
|
248
|
-
# Set attribute.
|
249
|
-
self.lock = TRLock()
|
250
|
-
self.acquire_thread_id: int | None = None
|
251
|
-
|
252
|
-
|
253
|
-
def acquire(
|
254
|
-
self,
|
255
|
-
timeout: float = None
|
256
|
-
) -> bool:
|
257
|
-
"""
|
258
|
-
Wait and acquire thread lock.
|
259
|
-
|
260
|
-
Parameters
|
261
|
-
----------
|
262
|
-
timeout : Maximum wait seconds.
|
263
|
-
- `None`: Not limit.
|
264
|
-
- `float`: Use this value.
|
265
|
-
|
266
|
-
Returns
|
267
|
-
-------
|
268
|
-
Whether acquire success.
|
269
|
-
"""
|
270
|
-
|
271
|
-
# Handle parameter.
|
272
|
-
if timeout is None:
|
273
|
-
timeout = -1
|
274
|
-
|
275
|
-
# Acquire.
|
276
|
-
result = self.lock.acquire(timeout=timeout)
|
277
|
-
|
278
|
-
# Update attribute.
|
279
|
-
if result:
|
280
|
-
thread_id = threading_get_ident()
|
281
|
-
self.acquire_thread_id = thread_id
|
282
|
-
|
283
|
-
return result
|
284
|
-
|
285
|
-
|
286
|
-
def release(self) -> None:
|
287
|
-
"""
|
288
|
-
Release thread lock.
|
289
|
-
"""
|
290
|
-
|
291
|
-
# Release.
|
292
|
-
self.lock.release()
|
293
|
-
|
294
|
-
# Update attribute.
|
295
|
-
self.acquire_thread_id = None
|
296
|
-
|
297
|
-
|
298
|
-
def __call__(self) -> None:
|
299
|
-
"""
|
300
|
-
Automatic judge, wait and acquire thread lock, or release thread lock.
|
301
|
-
"""
|
302
|
-
|
303
|
-
# Release.
|
304
|
-
thread_id = threading_get_ident()
|
305
|
-
if thread_id == self.acquire_thread_id:
|
306
|
-
self.release()
|
307
|
-
|
308
|
-
# Acquire.
|
309
|
-
else:
|
310
|
-
self.acquire()
|
311
|
-
|
312
|
-
|
313
|
-
class RAsyncLock():
|
314
|
-
"""
|
315
|
-
Rey's `asynchronous lock` type.
|
316
|
-
"""
|
317
|
-
|
318
|
-
|
319
|
-
def __init__(self) -> None:
|
320
|
-
"""
|
321
|
-
Build `asynchronous lock` attributes.
|
322
|
-
"""
|
323
|
-
|
324
|
-
# Set attribute.
|
325
|
-
self.lock = ALock()
|
326
|
-
|
327
|
-
|
328
|
-
def acquire(
|
329
|
-
self,
|
330
|
-
timeout: float = None
|
331
|
-
) -> bool:
|
332
|
-
"""
|
333
|
-
Wait and acquire thread lock.
|
334
|
-
|
335
|
-
Parameters
|
336
|
-
----------
|
337
|
-
timeout : Maximum wait seconds.
|
338
|
-
- `None`: Not limit.
|
339
|
-
- `float`: Use this value.
|
340
|
-
|
341
|
-
Returns
|
342
|
-
-------
|
343
|
-
Whether acquire success.
|
344
|
-
"""
|
345
|
-
|
346
|
-
# Handle parameter.
|
347
|
-
if timeout is None:
|
348
|
-
timeout = -1
|
349
|
-
|
350
|
-
# Acquire.
|
351
|
-
result = self.lock.acquire()
|
352
|
-
|
353
|
-
return result
|
354
|
-
|
355
|
-
|
356
|
-
def release(self) -> None:
|
357
|
-
"""
|
358
|
-
Release thread lock.
|
359
|
-
"""
|
360
|
-
|
361
|
-
# Release.
|
362
|
-
self.lock.release()
|
363
|
-
|
364
|
-
|
365
50
|
class RThreadPool(object):
|
366
51
|
"""
|
367
52
|
Rey's `thread pool` type.
|
368
53
|
"""
|
369
54
|
|
55
|
+
Queue = QQueue
|
56
|
+
Lock = TRLock
|
57
|
+
|
370
58
|
|
371
59
|
def __init__(
|
372
60
|
self,
|
@@ -381,18 +69,18 @@ class RThreadPool(object):
|
|
381
69
|
Parameters
|
382
70
|
----------
|
383
71
|
task : Thread task.
|
384
|
-
args :
|
72
|
+
args : ATask default position arguments.
|
385
73
|
_max_workers : Maximum number of threads.
|
386
74
|
- `None`: Number of CPU + 4, 32 maximum.
|
387
75
|
- `int`: Use this value, no maximum limit.
|
388
|
-
kwargs :
|
76
|
+
kwargs : ATask default keyword arguments.
|
389
77
|
"""
|
390
78
|
|
391
79
|
# Set attribute.
|
392
80
|
self.task = task
|
393
81
|
self.args = args
|
394
82
|
self.kwargs = kwargs
|
395
|
-
self.
|
83
|
+
self.pool = ThreadPoolExecutor(
|
396
84
|
_max_workers,
|
397
85
|
task.__name__
|
398
86
|
)
|
@@ -405,16 +93,16 @@ class RThreadPool(object):
|
|
405
93
|
**kwargs: Any
|
406
94
|
) -> CFuture:
|
407
95
|
"""
|
408
|
-
|
96
|
+
Start a task.
|
409
97
|
|
410
98
|
Parameters
|
411
99
|
----------
|
412
|
-
args :
|
413
|
-
kwargs :
|
100
|
+
args : ATask position arguments, after default position arguments.
|
101
|
+
kwargs : ATask keyword arguments, after default keyword arguments.
|
414
102
|
|
415
103
|
Returns
|
416
104
|
-------
|
417
|
-
|
105
|
+
ATask instance.
|
418
106
|
"""
|
419
107
|
|
420
108
|
# Set parameter.
|
@@ -427,8 +115,8 @@ class RThreadPool(object):
|
|
427
115
|
**kwargs
|
428
116
|
}
|
429
117
|
|
430
|
-
#
|
431
|
-
future = self.
|
118
|
+
# Add.
|
119
|
+
future = self.pool.submit(
|
432
120
|
self.task,
|
433
121
|
*func_args,
|
434
122
|
**func_kwargs
|
@@ -446,7 +134,7 @@ class RThreadPool(object):
|
|
446
134
|
**kwargs: tuple
|
447
135
|
) -> list[CFuture]:
|
448
136
|
"""
|
449
|
-
|
137
|
+
Batch start tasks.
|
450
138
|
parameters sequence will combine one by one, and discard excess parameters.
|
451
139
|
|
452
140
|
Parameters
|
@@ -456,7 +144,7 @@ class RThreadPool(object):
|
|
456
144
|
|
457
145
|
Returns
|
458
146
|
-------
|
459
|
-
|
147
|
+
ATask instance list.
|
460
148
|
|
461
149
|
Examples
|
462
150
|
--------
|
@@ -484,7 +172,7 @@ class RThreadPool(object):
|
|
484
172
|
)
|
485
173
|
params_zip = zip(args_zip, kwargs_zip)
|
486
174
|
|
487
|
-
# Batch
|
175
|
+
# Batch add.
|
488
176
|
futures = [
|
489
177
|
self.one(*args_, **dict(kwargs_))
|
490
178
|
for args_, kwargs_ in params_zip
|
@@ -496,6 +184,34 @@ class RThreadPool(object):
|
|
496
184
|
return futures
|
497
185
|
|
498
186
|
|
187
|
+
def repeat(
|
188
|
+
self,
|
189
|
+
number: int
|
190
|
+
) -> list[CFuture]:
|
191
|
+
"""
|
192
|
+
Batch start tasks, and only with default parameters.
|
193
|
+
|
194
|
+
Parameters
|
195
|
+
----------
|
196
|
+
number : Number of add.
|
197
|
+
|
198
|
+
Returns
|
199
|
+
-------
|
200
|
+
ATask instance list.
|
201
|
+
"""
|
202
|
+
|
203
|
+
# Batch add.
|
204
|
+
futures = [
|
205
|
+
self.one()
|
206
|
+
for _ in range(number)
|
207
|
+
]
|
208
|
+
|
209
|
+
# Save.
|
210
|
+
self.futures.extend(futures)
|
211
|
+
|
212
|
+
return futures
|
213
|
+
|
214
|
+
|
499
215
|
def generate(
|
500
216
|
self,
|
501
217
|
timeout: float | None = None
|
@@ -514,80 +230,439 @@ class RThreadPool(object):
|
|
514
230
|
Generator of added task instance.
|
515
231
|
"""
|
516
232
|
|
517
|
-
# Get parameter.
|
518
|
-
self.futures, futures = [], self.futures
|
519
|
-
|
520
233
|
# Build.
|
521
234
|
generator = concurrent_as_completed(
|
522
|
-
futures,
|
235
|
+
self.futures,
|
523
236
|
timeout
|
524
237
|
)
|
525
238
|
|
526
|
-
return generator
|
239
|
+
return generator
|
240
|
+
|
241
|
+
|
242
|
+
def join(
|
243
|
+
self,
|
244
|
+
timeout: float | None = None
|
245
|
+
) -> None:
|
246
|
+
"""
|
247
|
+
Block until all tasks are done.
|
248
|
+
|
249
|
+
Parameters
|
250
|
+
----------
|
251
|
+
timeout : Call generator maximum waiting seconds, timeout throw exception.
|
252
|
+
- `None`: Infinite.
|
253
|
+
- `float`: Set this seconds.
|
254
|
+
"""
|
255
|
+
|
256
|
+
# Generator.
|
257
|
+
generator = self.generate(timeout)
|
258
|
+
|
259
|
+
# Wait.
|
260
|
+
for _ in generator:
|
261
|
+
pass
|
262
|
+
|
263
|
+
|
264
|
+
def __iter__(self) -> Generator:
|
265
|
+
"""
|
266
|
+
Return the generator of task result.
|
267
|
+
|
268
|
+
Returns
|
269
|
+
-------
|
270
|
+
Generator of task result.
|
271
|
+
"""
|
272
|
+
|
273
|
+
# Generator.
|
274
|
+
generator = self.generate()
|
275
|
+
self.futures.clear()
|
276
|
+
|
277
|
+
# Generate.
|
278
|
+
for future in generator:
|
279
|
+
yield future.result()
|
280
|
+
|
281
|
+
|
282
|
+
@property
|
283
|
+
def thread_id(self) -> int:
|
284
|
+
"""
|
285
|
+
Get current thread ID.
|
286
|
+
|
287
|
+
Returns
|
288
|
+
-------
|
289
|
+
Current thread ID.
|
290
|
+
"""
|
291
|
+
|
292
|
+
# Get.
|
293
|
+
thread_id = threading_get_ident()
|
294
|
+
|
295
|
+
return thread_id
|
296
|
+
|
297
|
+
|
298
|
+
__call__ = one
|
299
|
+
|
300
|
+
|
301
|
+
__mul__ = repeat
|
302
|
+
|
303
|
+
|
304
|
+
@overload
|
305
|
+
def async_run(
|
306
|
+
coroutine: Coroutine[Any, Any, T] | ATask[Any, Any, T] | Callable[[], Coroutine[Any, Any, T]],
|
307
|
+
*,
|
308
|
+
return_exceptions: bool = False
|
309
|
+
) -> T: ...
|
310
|
+
|
311
|
+
@overload
|
312
|
+
def async_run(
|
313
|
+
*coroutines: Coroutine[Any, Any, T] | ATask[Any, Any, T] | Callable[[], Coroutine[Any, Any, T]],
|
314
|
+
return_exceptions: bool = False
|
315
|
+
) -> list[T]: ...
|
316
|
+
|
317
|
+
def async_run(
|
318
|
+
*coroutines: Coroutine[Any, Any, T] | ATask[Any, Any, T] | Callable[[], Coroutine[Any, Any, T]],
|
319
|
+
return_exceptions: bool = False
|
320
|
+
) -> T | list[T]:
|
321
|
+
"""
|
322
|
+
Asynchronous run coroutines.
|
323
|
+
|
324
|
+
Parameters
|
325
|
+
----------
|
326
|
+
coroutines : `Coroutine` instances or `ATask` instances or `Coroutine` function.
|
327
|
+
return_exceptions : Whether return exception instances, otherwise throw first exception.
|
328
|
+
|
329
|
+
Returns
|
330
|
+
-------
|
331
|
+
run results.
|
332
|
+
"""
|
333
|
+
|
334
|
+
# Handle parameter.
|
335
|
+
coroutines = [
|
336
|
+
coroutine()
|
337
|
+
if asyncio_iscoroutinefunction(coroutine)
|
338
|
+
else coroutine
|
339
|
+
for coroutine in coroutines
|
340
|
+
]
|
341
|
+
|
342
|
+
# Define.
|
343
|
+
async def async_run_coroutine() -> list:
|
344
|
+
"""
|
345
|
+
Asynchronous run coroutines.
|
346
|
+
|
347
|
+
Returns
|
348
|
+
-------
|
349
|
+
Run result list.
|
350
|
+
"""
|
351
|
+
|
352
|
+
# Gather.
|
353
|
+
results = await asyncio_gather(*coroutines, return_exceptions=return_exceptions)
|
354
|
+
|
355
|
+
return results
|
356
|
+
|
357
|
+
|
358
|
+
# Run.
|
359
|
+
coroutine = async_run_coroutine()
|
360
|
+
results = asyncio_run(coroutine)
|
361
|
+
|
362
|
+
# One.
|
363
|
+
if len(results) == 1:
|
364
|
+
results = results[0]
|
365
|
+
|
366
|
+
return results
|
367
|
+
|
368
|
+
|
369
|
+
@overload
|
370
|
+
async def async_sleep(
|
371
|
+
*,
|
372
|
+
precision: None = None
|
373
|
+
) -> int: ...
|
374
|
+
|
375
|
+
@overload
|
376
|
+
async def async_sleep(
|
377
|
+
second: int,
|
378
|
+
*,
|
379
|
+
precision: None = None
|
380
|
+
) -> int: ...
|
381
|
+
|
382
|
+
@overload
|
383
|
+
async def async_sleep(
|
384
|
+
low: int = 0,
|
385
|
+
high: int = 10,
|
386
|
+
*,
|
387
|
+
precision: None = None
|
388
|
+
) -> int: ...
|
389
|
+
|
390
|
+
@overload
|
391
|
+
async def async_sleep(
|
392
|
+
*thresholds: float,
|
393
|
+
precision: None = None
|
394
|
+
) -> float: ...
|
395
|
+
|
396
|
+
@overload
|
397
|
+
async def async_sleep(
|
398
|
+
*thresholds: float,
|
399
|
+
precision: Literal[0] = None
|
400
|
+
) -> int: ...
|
401
|
+
|
402
|
+
@overload
|
403
|
+
async def async_sleep(
|
404
|
+
*thresholds: float,
|
405
|
+
precision: int = None
|
406
|
+
) -> float: ...
|
407
|
+
|
408
|
+
async def async_sleep(
|
409
|
+
*thresholds: float,
|
410
|
+
precision: int | None = None
|
411
|
+
) -> float:
|
412
|
+
"""
|
413
|
+
Sleep random seconds, in the coroutine.
|
414
|
+
|
415
|
+
Parameters
|
416
|
+
----------
|
417
|
+
thresholds : Low and high thresholds of random range, range contains thresholds.
|
418
|
+
- When `length is 0`, then low and high thresholds is `0` and `10`.
|
419
|
+
- When `length is 1`, then sleep this value.
|
420
|
+
- When `length is 2`, then low and high thresholds is `thresholds[0]` and `thresholds[1]`.
|
421
|
+
|
422
|
+
precision : Precision of random range, that is maximum decimal digits of sleep seconds.
|
423
|
+
- `None`: Set to Maximum decimal digits of element of parameter `thresholds`.
|
424
|
+
- `int`: Set to this value.
|
425
|
+
|
426
|
+
Returns
|
427
|
+
-------
|
428
|
+
Random seconds.
|
429
|
+
- When parameters `precision` is `0`, then return int.
|
430
|
+
- When parameters `precision` is `greater than 0`, then return float.
|
431
|
+
"""
|
432
|
+
|
433
|
+
# Handle parameter.
|
434
|
+
if len(thresholds) == 1:
|
435
|
+
second = thresholds[0]
|
436
|
+
else:
|
437
|
+
second = randn(*thresholds, precision=precision)
|
438
|
+
|
439
|
+
# Sleep.
|
440
|
+
await asyncio_sleep(second)
|
441
|
+
|
442
|
+
return second
|
443
|
+
|
444
|
+
|
445
|
+
async def async_wait(
|
446
|
+
func: Callable[..., bool],
|
447
|
+
*args: Any,
|
448
|
+
_interval: float = 1,
|
449
|
+
_timeout: float | None = None,
|
450
|
+
_raising: bool = True,
|
451
|
+
**kwargs: Any
|
452
|
+
) -> float | None:
|
453
|
+
"""
|
454
|
+
Wait success.
|
455
|
+
|
456
|
+
Parameters
|
457
|
+
----------
|
458
|
+
func : Function to be decorated, must return `bool` value.
|
459
|
+
args : Position arguments of decorated function.
|
460
|
+
_interval : Interval seconds.
|
461
|
+
_timeout : Timeout seconds, timeout throw exception.
|
462
|
+
- `None`: Infinite time.
|
463
|
+
- `float`: Use this time.
|
464
|
+
_raising : When timeout, whether throw exception, otherwise return None.
|
465
|
+
kwargs : Keyword arguments of decorated function.
|
466
|
+
|
467
|
+
Returns
|
468
|
+
-------
|
469
|
+
Total spend seconds or None.
|
470
|
+
"""
|
471
|
+
|
472
|
+
# Set parameter.
|
473
|
+
rtm = RTimeMark()
|
474
|
+
rtm()
|
475
|
+
|
476
|
+
# Not set timeout.
|
477
|
+
if _timeout is None:
|
478
|
+
|
479
|
+
## Wait.
|
480
|
+
while True:
|
481
|
+
success = func(*args, **kwargs)
|
482
|
+
if success: break
|
483
|
+
await async_sleep(_interval)
|
484
|
+
|
485
|
+
# Set timeout.
|
486
|
+
else:
|
487
|
+
|
488
|
+
## Wait.
|
489
|
+
while True:
|
490
|
+
success = func(*args, **kwargs)
|
491
|
+
if success: break
|
492
|
+
|
493
|
+
## Timeout.
|
494
|
+
rtm()
|
495
|
+
if rtm.total_spend > _timeout:
|
496
|
+
|
497
|
+
### Throw exception.
|
498
|
+
if _raising:
|
499
|
+
throw(TimeoutError, _timeout)
|
500
|
+
|
501
|
+
return
|
502
|
+
|
503
|
+
## Sleep.
|
504
|
+
await async_sleep(_interval)
|
505
|
+
|
506
|
+
## Return.
|
507
|
+
rtm()
|
508
|
+
return rtm.total_spend
|
509
|
+
|
510
|
+
|
511
|
+
async def async_request(
|
512
|
+
url: str,
|
513
|
+
params: dict | None = None,
|
514
|
+
data: dict | str | bytes | None = None,
|
515
|
+
json: dict | None = None,
|
516
|
+
headers: dict[str, str] = {},
|
517
|
+
timeout: float | None = None,
|
518
|
+
proxy: str | None = None,
|
519
|
+
method: Literal['get', 'post', 'put', 'patch', 'delete', 'options', 'head'] | None = None,
|
520
|
+
check: bool | int | Iterable[int] = False,
|
521
|
+
handler: str | tuple[str] | Callable[[ClientResponse], Coroutine | Any] | None = None
|
522
|
+
) -> Any:
|
523
|
+
"""
|
524
|
+
Get asynchronous `Coroutine` instance of send request.
|
525
|
+
|
526
|
+
Parameters
|
527
|
+
----------
|
528
|
+
url : Request URL.
|
529
|
+
params : Request URL add parameters.
|
530
|
+
data : Request body data. Conflict with parameter `json`.
|
531
|
+
- `dict`, Convert to `key=value&...`: format bytes.
|
532
|
+
Automatic set `Content-Type` to `application/x-www-form-urlencoded`.
|
533
|
+
- `dict and a certain value is 'bytes' type`: Key is parameter name and file name, value is file data.
|
534
|
+
Automatic set `Content-Type` to `multipart/form-data`.
|
535
|
+
- `str`: File path to read file bytes data.
|
536
|
+
Automatic set `Content-Type` to file media type, and `filename` to file name.
|
537
|
+
- `bytes`: File bytes data.
|
538
|
+
Automatic set `Content-Type` to file media type.
|
539
|
+
json : Request body data, convert to `JSON` format. Conflict with parameter `data`.
|
540
|
+
Automatic set `Content-Type` to `application/json`.
|
541
|
+
headers : Request header data.
|
542
|
+
timeout : Request maximun waiting time.
|
543
|
+
proxy : Proxy URL.
|
544
|
+
method : Request method.
|
545
|
+
- `None`: Automatic judge.
|
546
|
+
When parameter `data` or `json` not has value, then request method is `get`.
|
547
|
+
When parameter `data` or `json` has value, then request method is `post`.
|
548
|
+
- `Literal['get', 'post', 'put', 'patch', 'delete', 'options', 'head']`: Use this request method.
|
549
|
+
check : Check response code, and throw exception.
|
550
|
+
- `Literal[False]`: Not check.
|
551
|
+
- `Literal[True]`: Check if is between 200 and 299.
|
552
|
+
- `int`: Check if is this value.
|
553
|
+
- `Iterable`: Check if is in sequence.
|
554
|
+
handler : Response handler.
|
555
|
+
- `None`: Automatic handle.
|
556
|
+
`Response 'Content-Type' is 'application/json'`: Use `ClientResponse.json` method.
|
557
|
+
`Response 'Content-Type' is 'text/plain; charset=utf-8'`: Use `ClientResponse.text` method.
|
558
|
+
`Other`: Use `ClientResponse.read` method.
|
559
|
+
- `str`: Get this attribute.
|
560
|
+
`Callable`: Execute this method. When return `Coroutine`, then use `await` syntax execute `Coroutine`.
|
561
|
+
`Any`: Return this value.
|
562
|
+
- `tuple[str]`: Get these attribute.
|
563
|
+
`Callable`: Execute this method. When return `Coroutine`, then use `await` syntax execute `Coroutine`.
|
564
|
+
`Any`: Return this value.
|
565
|
+
- `Callable`, Execute this method. When return `Coroutine`, then use `await`: syntax execute `Coroutine`.
|
566
|
+
|
567
|
+
Returns
|
568
|
+
-------
|
569
|
+
Response handler result.
|
570
|
+
"""
|
527
571
|
|
572
|
+
# Check.
|
573
|
+
check_most_one(data, json)
|
528
574
|
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
575
|
+
# Handle parameter.
|
576
|
+
if method is None:
|
577
|
+
if data is None and json is None:
|
578
|
+
method = 'get'
|
579
|
+
else:
|
580
|
+
method = 'post'
|
535
581
|
|
536
|
-
|
537
|
-
|
538
|
-
number : Number of add.
|
582
|
+
# Session.
|
583
|
+
async with ClientSession() as session:
|
539
584
|
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
585
|
+
# Request.
|
586
|
+
async with session.request(
|
587
|
+
method,
|
588
|
+
url,
|
589
|
+
params=params,
|
590
|
+
data=data,
|
591
|
+
json=json,
|
592
|
+
headers=headers,
|
593
|
+
timeout=timeout,
|
594
|
+
proxy=proxy
|
595
|
+
) as response:
|
544
596
|
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
597
|
+
# Check code.
|
598
|
+
if check is not False:
|
599
|
+
if check is True:
|
600
|
+
range_ = None
|
601
|
+
else:
|
602
|
+
range_ = check
|
603
|
+
check_response_code(response.status, range_)
|
550
604
|
|
551
|
-
|
552
|
-
|
605
|
+
# Receive.
|
606
|
+
match handler:
|
553
607
|
|
554
|
-
|
608
|
+
## Auto.
|
609
|
+
case None:
|
610
|
+
match response.content_type:
|
611
|
+
case 'application/json':
|
612
|
+
result = await response.json()
|
613
|
+
case 'text/plain; charset=utf-8':
|
555
614
|
|
615
|
+
# Set encode type.
|
616
|
+
if response.get_encoding() == 'ISO-8859-1':
|
617
|
+
encoding = 'utf-8'
|
618
|
+
else:
|
619
|
+
encoding = None
|
556
620
|
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
"""
|
621
|
+
result = await response.text(encoding=encoding)
|
622
|
+
case _:
|
623
|
+
result = await response.read()
|
561
624
|
|
562
|
-
|
563
|
-
|
625
|
+
## Attribute.
|
626
|
+
case str():
|
627
|
+
result = getattr(response, handler)
|
564
628
|
|
565
|
-
|
566
|
-
|
567
|
-
|
629
|
+
### Method.
|
630
|
+
if callable(result):
|
631
|
+
result = result()
|
568
632
|
|
633
|
+
#### Coroutine.
|
634
|
+
if asyncio_iscoroutine(result):
|
635
|
+
result = await result
|
569
636
|
|
570
|
-
|
571
|
-
|
572
|
-
|
637
|
+
## Attributes.
|
638
|
+
case tuple():
|
639
|
+
result = []
|
640
|
+
for key in handler:
|
641
|
+
result_element = getattr(response, key)
|
573
642
|
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
"""
|
643
|
+
### Method.
|
644
|
+
if callable(result_element):
|
645
|
+
result_element = result_element()
|
578
646
|
|
579
|
-
|
580
|
-
|
647
|
+
#### Coroutine.
|
648
|
+
if asyncio_iscoroutine(result_element):
|
649
|
+
result_element = await result_element
|
581
650
|
|
582
|
-
|
583
|
-
for future in generator:
|
584
|
-
yield future.result()
|
651
|
+
result.append(result_element)
|
585
652
|
|
653
|
+
## Method.
|
654
|
+
case _ if callable(handler):
|
655
|
+
result = handler(response)
|
586
656
|
|
587
|
-
|
657
|
+
### Coroutine.
|
658
|
+
if asyncio_iscoroutine(result):
|
659
|
+
result = await result
|
588
660
|
|
661
|
+
## Throw exception.
|
662
|
+
case _:
|
663
|
+
throw(TypeError, handler)
|
589
664
|
|
590
|
-
|
665
|
+
return result
|
591
666
|
|
592
667
|
|
593
668
|
class RAsyncPool(object):
|
@@ -595,13 +670,14 @@ class RAsyncPool(object):
|
|
595
670
|
Rey's `asynchronous pool` type.
|
596
671
|
"""
|
597
672
|
|
673
|
+
Queue = AQueue
|
674
|
+
Lock = ALock
|
675
|
+
|
598
676
|
|
599
677
|
def __init__(
|
600
678
|
self,
|
601
|
-
|
679
|
+
task: Callable[..., Coroutine],
|
602
680
|
*args: Any,
|
603
|
-
_max_async: int = 10,
|
604
|
-
_exc_handler: Callable | None = None,
|
605
681
|
**kwargs: Any
|
606
682
|
) -> None:
|
607
683
|
"""
|
@@ -611,76 +687,31 @@ class RAsyncPool(object):
|
|
611
687
|
----------
|
612
688
|
async_func : Function of create asynchronous `Coroutine`.
|
613
689
|
args : Function default position arguments.
|
614
|
-
_max_async : Maximum number of asynchronous.
|
615
|
-
_exc_handler : `Coroutine` execution exception handler, will return value.
|
616
690
|
kwargs : Function default keyword arguments.
|
617
691
|
"""
|
618
692
|
|
619
693
|
# Set attribute.
|
620
|
-
self.
|
694
|
+
self.task = task
|
621
695
|
self.args = args
|
622
696
|
self.kwargs = kwargs
|
623
|
-
self.
|
624
|
-
self.
|
625
|
-
self.queue_output = AQueue()
|
626
|
-
self.queue_count = 0
|
697
|
+
self.loop = asyncio_new_event_loop()
|
698
|
+
self.futures: list[AFuture] = []
|
627
699
|
|
628
700
|
# Start.
|
629
|
-
self.
|
701
|
+
self._start_loop()
|
630
702
|
|
631
703
|
|
632
704
|
@wrap_thread
|
633
|
-
def
|
634
|
-
self,
|
635
|
-
worker_n: int
|
636
|
-
) -> None:
|
705
|
+
def _start_loop(self) -> None:
|
637
706
|
"""
|
638
|
-
Start
|
639
|
-
|
640
|
-
Parameters
|
641
|
-
----------
|
642
|
-
worker_n : Number of execute asynchronous `Coroutine` workers.
|
707
|
+
Start event loop.
|
643
708
|
"""
|
644
709
|
|
710
|
+
# Set.
|
711
|
+
asyncio_set_event_loop(self.loop)
|
645
712
|
|
646
|
-
|
647
|
-
|
648
|
-
"""
|
649
|
-
Worker of execute asynchronous `Coroutine`.
|
650
|
-
"""
|
651
|
-
|
652
|
-
# Loop.
|
653
|
-
while True:
|
654
|
-
|
655
|
-
# Get parameter.
|
656
|
-
args, kwargs = await self.queue_input.get()
|
657
|
-
|
658
|
-
# Execute.
|
659
|
-
try:
|
660
|
-
result = await self.async_func(*args, **kwargs)
|
661
|
-
|
662
|
-
# Handle exception.
|
663
|
-
except:
|
664
|
-
if self.exc_handler is not None:
|
665
|
-
result = self.exc_handler()
|
666
|
-
await self.queue_output.put(result)
|
667
|
-
|
668
|
-
## Count.
|
669
|
-
else:
|
670
|
-
self.queue_count -= 1
|
671
|
-
|
672
|
-
else:
|
673
|
-
await self.queue_output.put(result)
|
674
|
-
|
675
|
-
|
676
|
-
# Create.
|
677
|
-
coroutines = [
|
678
|
-
async_worker()
|
679
|
-
for _ in range(worker_n)
|
680
|
-
]
|
681
|
-
|
682
|
-
# Start.
|
683
|
-
async_run(*coroutines)
|
713
|
+
## Start and block.
|
714
|
+
self.loop.run_forever()
|
684
715
|
|
685
716
|
|
686
717
|
def one(
|
@@ -689,7 +720,7 @@ class RAsyncPool(object):
|
|
689
720
|
**kwargs: Any
|
690
721
|
) -> None:
|
691
722
|
"""
|
692
|
-
|
723
|
+
Start a task.
|
693
724
|
|
694
725
|
Parameters
|
695
726
|
----------
|
@@ -706,16 +737,15 @@ class RAsyncPool(object):
|
|
706
737
|
**self.kwargs,
|
707
738
|
**kwargs
|
708
739
|
}
|
709
|
-
item = (
|
710
|
-
func_args,
|
711
|
-
func_kwargs
|
712
|
-
)
|
713
740
|
|
714
|
-
#
|
715
|
-
self.
|
741
|
+
# Create.
|
742
|
+
coroutine = self.task(*func_args, **func_kwargs)
|
743
|
+
|
744
|
+
# Add.
|
745
|
+
future = asyncio_run_coroutine_threadsafe(coroutine, self.loop)
|
716
746
|
|
717
|
-
#
|
718
|
-
self.
|
747
|
+
# Save.
|
748
|
+
self.futures.append(future)
|
719
749
|
|
720
750
|
|
721
751
|
def batch(
|
@@ -724,7 +754,7 @@ class RAsyncPool(object):
|
|
724
754
|
**kwargs: tuple
|
725
755
|
) -> None:
|
726
756
|
"""
|
727
|
-
|
757
|
+
Batch start tasks.
|
728
758
|
parameters sequence will combine one by one, and discard excess parameters.
|
729
759
|
|
730
760
|
Parameters
|
@@ -759,7 +789,7 @@ class RAsyncPool(object):
|
|
759
789
|
)
|
760
790
|
params_zip = zip(args_zip, kwargs_zip)
|
761
791
|
|
762
|
-
# Batch
|
792
|
+
# Batch add.
|
763
793
|
for args_, kwargs_ in params_zip:
|
764
794
|
self.one(*args_, **dict(kwargs_))
|
765
795
|
|
@@ -769,167 +799,95 @@ class RAsyncPool(object):
|
|
769
799
|
number: int
|
770
800
|
) -> list[CFuture]:
|
771
801
|
"""
|
772
|
-
|
802
|
+
Batch start tasks, and only with default parameters.
|
773
803
|
|
774
804
|
Parameters
|
775
805
|
----------
|
776
806
|
number : Number of add.
|
777
807
|
"""
|
778
808
|
|
779
|
-
# Batch
|
809
|
+
# Batch add.
|
780
810
|
for _ in range(number):
|
781
811
|
self.one()
|
782
812
|
|
783
813
|
|
784
|
-
def
|
814
|
+
def generate(
|
785
815
|
self,
|
786
816
|
timeout: float | None = None
|
787
|
-
) ->
|
817
|
+
) -> Generator[CFuture]:
|
788
818
|
"""
|
789
|
-
|
819
|
+
Return the generator of added task instance.
|
790
820
|
|
791
821
|
Parameters
|
792
822
|
----------
|
793
|
-
timeout :
|
823
|
+
timeout : Call generator maximum waiting seconds, timeout throw exception.
|
824
|
+
- `None`: Infinite.
|
825
|
+
- `float`: Set this seconds.
|
794
826
|
|
795
827
|
Returns
|
796
828
|
-------
|
797
|
-
|
829
|
+
Generator of added task instance.
|
798
830
|
"""
|
799
831
|
|
800
|
-
#
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
# Loop.
|
806
|
-
while True:
|
807
|
-
|
808
|
-
# Judge.
|
809
|
-
if not self.queue_output.empty():
|
810
|
-
|
811
|
-
# Get.
|
812
|
-
try:
|
813
|
-
result = self.queue_output.get_nowait()
|
814
|
-
except QueueEmpty:
|
815
|
-
pass
|
816
|
-
else:
|
817
|
-
|
818
|
-
# Count.
|
819
|
-
self.queue_count -= 1
|
820
|
-
|
821
|
-
return result
|
822
|
-
|
823
|
-
# Timeout.
|
824
|
-
if timeout is not None:
|
825
|
-
rtm()
|
826
|
-
if rtm.total_spend > timeout:
|
827
|
-
throw(TimeoutError, timeout)
|
832
|
+
# Build.
|
833
|
+
generator = concurrent_as_completed(
|
834
|
+
self.futures,
|
835
|
+
timeout
|
836
|
+
)
|
828
837
|
|
829
|
-
|
830
|
-
sleep(0.01)
|
838
|
+
return generator
|
831
839
|
|
832
840
|
|
833
|
-
def join(
|
834
|
-
|
835
|
-
|
841
|
+
def join(
|
842
|
+
self,
|
843
|
+
timeout: float | None = None
|
844
|
+
) -> None:
|
836
845
|
"""
|
846
|
+
Block until all tasks are done.
|
837
847
|
|
838
|
-
|
839
|
-
|
848
|
+
Parameters
|
849
|
+
----------
|
850
|
+
timeout : Call generator maximum waiting seconds, timeout throw exception.
|
851
|
+
- `None`: Infinite.
|
852
|
+
- `float`: Set this seconds.
|
853
|
+
"""
|
840
854
|
|
841
|
-
|
842
|
-
|
843
|
-
break
|
855
|
+
# Generator.
|
856
|
+
generator = self.generate(timeout)
|
844
857
|
|
845
|
-
|
858
|
+
# Wait.
|
859
|
+
for _ in generator:
|
860
|
+
pass
|
846
861
|
|
847
862
|
|
848
863
|
def __iter__(self) -> Generator:
|
849
864
|
"""
|
850
|
-
Return the generator of result
|
865
|
+
Return the generator of task result.
|
851
866
|
|
852
867
|
Returns
|
853
868
|
-------
|
854
|
-
Generator of result
|
855
|
-
"""
|
856
|
-
|
857
|
-
# Generate.
|
858
|
-
while True:
|
859
|
-
|
860
|
-
# Break.
|
861
|
-
if self.queue_count == 0:
|
862
|
-
break
|
863
|
-
|
864
|
-
result = self.get()
|
865
|
-
yield result
|
866
|
-
|
867
|
-
|
868
|
-
__call__ = one
|
869
|
-
|
870
|
-
|
871
|
-
__mul__ = repeat
|
872
|
-
|
873
|
-
|
874
|
-
class RAsyncIterator(AsyncIterator):
|
875
|
-
"""
|
876
|
-
Rey's `asynchronous iterator` type.
|
877
|
-
"""
|
878
|
-
|
879
|
-
|
880
|
-
def __init__(
|
881
|
-
self,
|
882
|
-
task: Callable,
|
883
|
-
args_iter: Iterable[Iterable] | None = None,
|
884
|
-
kwargs_iter: Iterable[dict] | None = None
|
885
|
-
) -> None:
|
869
|
+
Generator of task result.
|
886
870
|
"""
|
887
|
-
Build `asynchronous iterator` attributes.
|
888
871
|
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
args_iter : Iterable of task position arguments.
|
893
|
-
kwargs_iter : Iterable of task keyword arguments.
|
894
|
-
"""
|
872
|
+
# Generator.
|
873
|
+
generator = self.generate()
|
874
|
+
self.futures.clear()
|
895
875
|
|
896
|
-
#
|
897
|
-
|
898
|
-
|
899
|
-
args_iter: Iterator[Iterable] = iter(args_iter)
|
900
|
-
self.args_iter = args_iter
|
901
|
-
if kwargs_iter is not None:
|
902
|
-
kwargs_iter: Iterator[dict] = iter(kwargs_iter)
|
903
|
-
self.kwargs_iter = kwargs_iter
|
876
|
+
# Generate.
|
877
|
+
for future in generator:
|
878
|
+
yield future.result()
|
904
879
|
|
905
880
|
|
906
|
-
def
|
881
|
+
def __del__(self) -> None:
|
907
882
|
"""
|
908
|
-
|
883
|
+
End loop.
|
909
884
|
"""
|
910
885
|
|
911
|
-
|
912
|
-
|
913
|
-
|
914
|
-
async def __anext__(self):
|
915
|
-
"""
|
916
|
-
Get next value from asynchronous iterator.
|
917
|
-
"""
|
886
|
+
# Stop.
|
887
|
+
self.loop.stop()
|
918
888
|
|
919
|
-
# Get parameter.
|
920
|
-
args = ()
|
921
|
-
kwargs = {}
|
922
889
|
|
923
|
-
|
924
|
-
try:
|
925
|
-
if self.args_iter is not None:
|
926
|
-
args = next(self.args_iter)
|
927
|
-
if self.kwargs_iter is not None:
|
928
|
-
kwargs = next(self.kwargs_iter)
|
929
|
-
except StopIteration:
|
930
|
-
raise StopAsyncIteration
|
890
|
+
__call__ = one
|
931
891
|
|
932
|
-
# Execute.
|
933
|
-
result = self.task(*args, **kwargs)
|
934
892
|
|
935
|
-
|
893
|
+
__mul__ = repeat
|