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