reykit 1.0.0__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/__init__.py +41 -0
- reykit/rall.py +33 -0
- reykit/rcomm.py +431 -0
- reykit/rdata.py +395 -0
- reykit/rdll/__init__.py +17 -0
- reykit/rdll/rdll_inject.py +41 -0
- reykit/rdll/rdll_inject_core.py +202 -0
- reykit/remail.py +276 -0
- reykit/rexception.py +339 -0
- reykit/rimage.py +261 -0
- reykit/rlog.py +1061 -0
- reykit/rmonkey.py +341 -0
- reykit/rmultitask.py +871 -0
- reykit/rnumber.py +161 -0
- reykit/ros.py +1917 -0
- reykit/rrandom.py +351 -0
- reykit/rregex.py +293 -0
- reykit/rschedule.py +272 -0
- reykit/rstdout.py +356 -0
- reykit/rsystem.py +1180 -0
- reykit/rtable.py +511 -0
- reykit/rtext.py +458 -0
- reykit/rtime.py +678 -0
- reykit/rtype.py +106 -0
- reykit/rwrap.py +613 -0
- reykit/rzip.py +137 -0
- reykit-1.0.0.dist-info/METADATA +29 -0
- reykit-1.0.0.dist-info/RECORD +30 -0
- reykit-1.0.0.dist-info/WHEEL +5 -0
- reykit-1.0.0.dist-info/top_level.txt +1 -0
reykit/rtype.py
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
# !/usr/bin/env python
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
|
4
|
+
"""
|
5
|
+
@Time : 2025-06-13 02:05:46
|
6
|
+
@Author : Rey
|
7
|
+
@Contact : reyxbo@163.com
|
8
|
+
@Explain : Type methods.
|
9
|
+
"""
|
10
|
+
|
11
|
+
|
12
|
+
from typing import Any, Optional, Self
|
13
|
+
from collections.abc import Callable
|
14
|
+
|
15
|
+
|
16
|
+
__all__ = (
|
17
|
+
'RStaticMeta',
|
18
|
+
'RConfigMeta',
|
19
|
+
'RNull',
|
20
|
+
'RSingleton'
|
21
|
+
)
|
22
|
+
|
23
|
+
|
24
|
+
class RStaticMeta(type):
|
25
|
+
"""
|
26
|
+
Rey's `static meta` type.
|
27
|
+
"""
|
28
|
+
|
29
|
+
|
30
|
+
def __call__(cls):
|
31
|
+
"""
|
32
|
+
Call method.
|
33
|
+
"""
|
34
|
+
|
35
|
+
# Throw exception.
|
36
|
+
raise TypeError('static class, no instances allowed.')
|
37
|
+
|
38
|
+
|
39
|
+
class RConfigMeta(RStaticMeta):
|
40
|
+
"""
|
41
|
+
Rey's `config meta` type.
|
42
|
+
"""
|
43
|
+
|
44
|
+
|
45
|
+
def __getitem__(cls, name: str):
|
46
|
+
"""
|
47
|
+
Get item.
|
48
|
+
|
49
|
+
Parameters
|
50
|
+
----------
|
51
|
+
name : Item name.
|
52
|
+
|
53
|
+
Returns
|
54
|
+
-------
|
55
|
+
Item value.
|
56
|
+
"""
|
57
|
+
|
58
|
+
# Get.
|
59
|
+
item = getattr(cls, name)
|
60
|
+
|
61
|
+
return item
|
62
|
+
|
63
|
+
|
64
|
+
def __setitem__(cls, name: str, value: Any) -> None:
|
65
|
+
"""
|
66
|
+
Set item.
|
67
|
+
|
68
|
+
Parameters
|
69
|
+
----------
|
70
|
+
name : Item name.
|
71
|
+
"""
|
72
|
+
|
73
|
+
# Set.
|
74
|
+
setattr(cls, name, value)
|
75
|
+
|
76
|
+
|
77
|
+
class RNull(object, metaclass=RStaticMeta):
|
78
|
+
"""
|
79
|
+
Rey's `null` type.
|
80
|
+
"""
|
81
|
+
|
82
|
+
|
83
|
+
class RSingleton(object):
|
84
|
+
"""
|
85
|
+
Rey's `singleton` type.
|
86
|
+
When instantiated, method `__singleton__` will be called only once, and will accept arguments.
|
87
|
+
"""
|
88
|
+
|
89
|
+
_instance: Optional[Self] = None
|
90
|
+
|
91
|
+
|
92
|
+
def __new__(self, *arg: Any, **kwargs: Any) -> Self:
|
93
|
+
"""
|
94
|
+
Build `singleton` instance.
|
95
|
+
"""
|
96
|
+
|
97
|
+
# Build.
|
98
|
+
if self._instance is None:
|
99
|
+
self._instance = super().__new__(self)
|
100
|
+
|
101
|
+
## Singleton method.
|
102
|
+
if hasattr(self, "__singleton__"):
|
103
|
+
__singleton__: Callable = getattr(self, "__singleton__")
|
104
|
+
__singleton__(self, *arg, **kwargs)
|
105
|
+
|
106
|
+
return self._instance
|
reykit/rwrap.py
ADDED
@@ -0,0 +1,613 @@
|
|
1
|
+
# !/usr/bin/env python
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
|
4
|
+
"""
|
5
|
+
@Time : 2022-12-05 14:12:25
|
6
|
+
@Author : Rey
|
7
|
+
@Contact : reyxbo@163.com
|
8
|
+
@Explain : Decorator methods.
|
9
|
+
"""
|
10
|
+
|
11
|
+
|
12
|
+
from typing import Any, Optional, Union, Literal, overload
|
13
|
+
from collections.abc import Callable
|
14
|
+
from io import IOBase, StringIO
|
15
|
+
from inspect import getdoc
|
16
|
+
from functools import wraps as functools_wraps
|
17
|
+
from threading import Thread
|
18
|
+
from argparse import ArgumentParser
|
19
|
+
from contextlib import redirect_stdout
|
20
|
+
|
21
|
+
from .rexception import catch_exc
|
22
|
+
from .rstdout import echo
|
23
|
+
from .rsystem import get_arg_info
|
24
|
+
from .rtime import now, time_to, RTimeMark
|
25
|
+
|
26
|
+
|
27
|
+
__all__ = (
|
28
|
+
'wrap_frame',
|
29
|
+
'wrap_runtime',
|
30
|
+
'wrap_thread',
|
31
|
+
'wrap_exc',
|
32
|
+
'wrap_retry',
|
33
|
+
'wrap_dos_command',
|
34
|
+
'wrap_cache_data',
|
35
|
+
'wrap_cache',
|
36
|
+
'wrap_redirect_stdout'
|
37
|
+
)
|
38
|
+
|
39
|
+
|
40
|
+
def wrap_frame(decorator: Callable) -> Callable:
|
41
|
+
"""
|
42
|
+
Decorative frame.
|
43
|
+
|
44
|
+
Parameters
|
45
|
+
----------
|
46
|
+
decorator : Decorator function.
|
47
|
+
|
48
|
+
Retuens
|
49
|
+
-------
|
50
|
+
Decorated decorator.
|
51
|
+
|
52
|
+
Examples
|
53
|
+
--------
|
54
|
+
Decoration function method one.
|
55
|
+
>>> @wrap_func
|
56
|
+
>>> def func(): ...
|
57
|
+
>>> result = func(param_a, param_b, param_c=1, param_d=2)
|
58
|
+
|
59
|
+
Decoration function method two.
|
60
|
+
>>> def func(): ...
|
61
|
+
>>> result = wrap_func(func, param_a, param_b, param_c=1, param_d=2)
|
62
|
+
|
63
|
+
Decoration function method three.
|
64
|
+
>>> def func(): ...
|
65
|
+
>>> result = wrap_func(func, _execute=True)
|
66
|
+
|
67
|
+
Decoration function method four.
|
68
|
+
>>> def func(): ...
|
69
|
+
>>> func = wrap_func(func)
|
70
|
+
>>> result = func(param_a, param_b, param_c=1, param_d=2)
|
71
|
+
|
72
|
+
Decoration function method five.
|
73
|
+
>>> def func(): ...
|
74
|
+
>>> func = wrap_func(func, param_a, param_c=1, _execute=False)
|
75
|
+
>>> result = func(param_b, param_d=2)
|
76
|
+
"""
|
77
|
+
|
78
|
+
|
79
|
+
# Decorate Decorator.
|
80
|
+
@overload
|
81
|
+
def wrap(func: Callable, *args: Any, _execute: None = None, **kwargs: Any) -> Union[Callable, Any]: ...
|
82
|
+
|
83
|
+
@overload
|
84
|
+
def wrap(func: Callable, *args: Any, _execute: Literal[True] = None, **kwargs: Any) -> Any: ...
|
85
|
+
|
86
|
+
@overload
|
87
|
+
def wrap(func: Callable, *args: Any, _execute: Literal[False] = None, **kwargs: Any) -> Callable: ...
|
88
|
+
|
89
|
+
@functools_wraps(decorator)
|
90
|
+
def wrap(func: Callable, *args: Any, _execute: Optional[bool] = None, **kwargs: Any) -> Union[Callable, Any]:
|
91
|
+
"""
|
92
|
+
Decorative shell.
|
93
|
+
|
94
|
+
Parameters
|
95
|
+
----------
|
96
|
+
func : Function.
|
97
|
+
args : Position arguments of function.
|
98
|
+
_execute : Whether execute function, otherwise decorate function.
|
99
|
+
- `None`, When parameter `args` or `kwargs`: have values, then True, otherwise False.
|
100
|
+
- `bool`: Use this value.
|
101
|
+
kwargs : Keyword arguments of function.
|
102
|
+
|
103
|
+
Returns
|
104
|
+
-------
|
105
|
+
Decorated function or function return.
|
106
|
+
"""
|
107
|
+
|
108
|
+
# Handle parameter.
|
109
|
+
if _execute is None:
|
110
|
+
if args != () or kwargs != {}:
|
111
|
+
_execute = True
|
112
|
+
else:
|
113
|
+
_execute = False
|
114
|
+
|
115
|
+
# Direct execution.
|
116
|
+
if _execute:
|
117
|
+
result = decorator(func, *args, **kwargs)
|
118
|
+
return result
|
119
|
+
|
120
|
+
|
121
|
+
# Decorate function.
|
122
|
+
@functools_wraps(func)
|
123
|
+
def wrap_sub(*_args: Any, **_kwargs: Any) -> Any:
|
124
|
+
"""
|
125
|
+
Decorative sub shell.
|
126
|
+
|
127
|
+
Parameters
|
128
|
+
----------
|
129
|
+
args : Position arguments of function.
|
130
|
+
kwargs : Keyword arguments of function.
|
131
|
+
|
132
|
+
Returns
|
133
|
+
-------
|
134
|
+
Function return.
|
135
|
+
"""
|
136
|
+
|
137
|
+
# Decorate function.
|
138
|
+
result = decorator(func, *args, *_args, **kwargs, **_kwargs)
|
139
|
+
|
140
|
+
return result
|
141
|
+
|
142
|
+
|
143
|
+
return wrap_sub
|
144
|
+
|
145
|
+
|
146
|
+
return wrap
|
147
|
+
|
148
|
+
|
149
|
+
@overload
|
150
|
+
def wrap_runtime(
|
151
|
+
func: Callable,
|
152
|
+
*args: Any,
|
153
|
+
_return_report: Literal[False] = False,
|
154
|
+
**kwargs: Any
|
155
|
+
) -> Any: ...
|
156
|
+
|
157
|
+
@overload
|
158
|
+
def wrap_runtime(func: Callable,
|
159
|
+
*args: Any,
|
160
|
+
_return_report: Literal[True] = False,
|
161
|
+
**kwargs: Any
|
162
|
+
) -> tuple[Any, str]: ...
|
163
|
+
|
164
|
+
@wrap_frame
|
165
|
+
def wrap_runtime(
|
166
|
+
func: Callable,
|
167
|
+
*args: Any,
|
168
|
+
_return_report: bool = False,
|
169
|
+
**kwargs: Any
|
170
|
+
) -> Union[Any, tuple[Any, str]]:
|
171
|
+
"""
|
172
|
+
Decorator, print or return runtime report of the function.
|
173
|
+
|
174
|
+
Parameters
|
175
|
+
----------
|
176
|
+
func : Function to be decorated.
|
177
|
+
args : Position arguments of decorated function.
|
178
|
+
_return_report : Whether return report, otherwise print report.
|
179
|
+
kwargs : Keyword arguments of decorated function.
|
180
|
+
|
181
|
+
Returns
|
182
|
+
-------
|
183
|
+
Function execution result and runtime report.
|
184
|
+
"""
|
185
|
+
|
186
|
+
# Execute function and marking time.
|
187
|
+
rtm = RTimeMark()
|
188
|
+
rtm()
|
189
|
+
result = func(*args, **kwargs)
|
190
|
+
rtm()
|
191
|
+
|
192
|
+
# Generate report.
|
193
|
+
start_time = rtm.record[0]['datetime']
|
194
|
+
spend_time = rtm.record[1]['timedelta']
|
195
|
+
end_time = rtm.record[1]['datetime']
|
196
|
+
start_str = time_to(start_time, True)[:-3]
|
197
|
+
spend_str = time_to(spend_time, True)[:-3]
|
198
|
+
end_str = time_to(end_time, True)[:-3]
|
199
|
+
report = 'Start: %s -> Spend: %ss -> End: %s' % (
|
200
|
+
start_str,
|
201
|
+
spend_str,
|
202
|
+
end_str
|
203
|
+
)
|
204
|
+
title = func.__name__
|
205
|
+
|
206
|
+
# Return report.
|
207
|
+
if _return_report:
|
208
|
+
return result, report
|
209
|
+
|
210
|
+
# Print report.
|
211
|
+
echo(report, title=title)
|
212
|
+
|
213
|
+
return result
|
214
|
+
|
215
|
+
|
216
|
+
@overload
|
217
|
+
def wrap_thread(
|
218
|
+
func: Callable,
|
219
|
+
*args: Any,
|
220
|
+
_daemon: bool = True,
|
221
|
+
**kwargs: Any
|
222
|
+
) -> Thread: ...
|
223
|
+
|
224
|
+
@wrap_frame
|
225
|
+
def wrap_thread(
|
226
|
+
func: Callable,
|
227
|
+
*args: Any,
|
228
|
+
_daemon: bool = True,
|
229
|
+
**kwargs: Any
|
230
|
+
) -> Thread:
|
231
|
+
"""
|
232
|
+
Decorator, function start in thread.
|
233
|
+
|
234
|
+
Parameters
|
235
|
+
----------
|
236
|
+
func : Function to be decorated.
|
237
|
+
args : Position arguments of decorated function.
|
238
|
+
_daemon : Whether it is a daemon thread.
|
239
|
+
kwargs : Keyword arguments of decorated function.
|
240
|
+
|
241
|
+
Returns
|
242
|
+
-------
|
243
|
+
Thread object.
|
244
|
+
"""
|
245
|
+
|
246
|
+
# Handle parameter.
|
247
|
+
thread_name = '%s_%d' % (func.__name__, now('timestamp'))
|
248
|
+
|
249
|
+
# Create thread.
|
250
|
+
thread = Thread(target=func, name=thread_name, args=args, kwargs=kwargs)
|
251
|
+
thread.daemon = _daemon
|
252
|
+
|
253
|
+
# Start thread.
|
254
|
+
thread.start()
|
255
|
+
|
256
|
+
return thread
|
257
|
+
|
258
|
+
|
259
|
+
@overload
|
260
|
+
def wrap_exc(
|
261
|
+
func: Callable,
|
262
|
+
*args: Any,
|
263
|
+
_exception: Union[BaseException, tuple[BaseException, ...]] = BaseException,
|
264
|
+
_handler: Optional[Callable] = None,
|
265
|
+
**kwargs: Any
|
266
|
+
) -> Optional[Any]: ...
|
267
|
+
|
268
|
+
@wrap_frame
|
269
|
+
def wrap_exc(
|
270
|
+
func: Callable,
|
271
|
+
*args: Any,
|
272
|
+
_exception: Union[BaseException, tuple[BaseException, ...]] = BaseException,
|
273
|
+
_handler: Optional[Callable] = None,
|
274
|
+
**kwargs: Any
|
275
|
+
) -> Optional[Any]:
|
276
|
+
"""
|
277
|
+
Decorator, execute function with `try` and `except` syntax.
|
278
|
+
|
279
|
+
Parameters
|
280
|
+
----------
|
281
|
+
func : Function to be decorated.
|
282
|
+
args : Position arguments of decorated function.
|
283
|
+
_exception : Catch exception types.
|
284
|
+
_handler : Exception handler, will return value.
|
285
|
+
kwargs : Keyword arguments of decorated function.
|
286
|
+
|
287
|
+
Returns
|
288
|
+
-------
|
289
|
+
Execution result of function or exception handle method.
|
290
|
+
"""
|
291
|
+
|
292
|
+
# Execute function.
|
293
|
+
try:
|
294
|
+
result = func(*args, **kwargs)
|
295
|
+
|
296
|
+
# Handle exception.
|
297
|
+
except _exception:
|
298
|
+
if _handler is not None:
|
299
|
+
result = _handler()
|
300
|
+
else:
|
301
|
+
result = None
|
302
|
+
|
303
|
+
return result
|
304
|
+
|
305
|
+
|
306
|
+
@overload
|
307
|
+
def wrap_retry(
|
308
|
+
func: Callable,
|
309
|
+
*args: Any,
|
310
|
+
_report: Optional[str] = None,
|
311
|
+
_exception: Union[BaseException, tuple[BaseException, ...]] = BaseException,
|
312
|
+
_try_total: int = 1,
|
313
|
+
_try_count: int = 0,
|
314
|
+
**kwargs: Any
|
315
|
+
) -> Any: ...
|
316
|
+
|
317
|
+
@wrap_frame
|
318
|
+
def wrap_retry(
|
319
|
+
func: Callable,
|
320
|
+
*args: Any,
|
321
|
+
_report: Optional[str] = None,
|
322
|
+
_exception: Union[BaseException, tuple[BaseException, ...]] = BaseException,
|
323
|
+
_try_total: int = 1,
|
324
|
+
_try_count: int = 0,
|
325
|
+
**kwargs: Any
|
326
|
+
) -> Any:
|
327
|
+
"""
|
328
|
+
Decorator, try again.
|
329
|
+
|
330
|
+
Parameters
|
331
|
+
----------
|
332
|
+
func : Function to be decorated.
|
333
|
+
args : Position arguments of decorated function.
|
334
|
+
_report : Print report title.
|
335
|
+
- `None`: Not print.
|
336
|
+
- `str`: Print and use this title.
|
337
|
+
_exception : Catch exception types.
|
338
|
+
_try_total : Retry total.
|
339
|
+
_try_count : Retry count.
|
340
|
+
kwargs : Keyword arguments of decorated function.
|
341
|
+
|
342
|
+
Returns
|
343
|
+
-------
|
344
|
+
Function execution result.
|
345
|
+
"""
|
346
|
+
|
347
|
+
# Try count not full.
|
348
|
+
if _try_count < _try_total:
|
349
|
+
|
350
|
+
## Try.
|
351
|
+
try:
|
352
|
+
result = func(*args, **kwargs)
|
353
|
+
except _exception:
|
354
|
+
|
355
|
+
## Report.
|
356
|
+
if _report is not None:
|
357
|
+
exc_report, *_ = catch_exc()
|
358
|
+
echo(
|
359
|
+
exc_report,
|
360
|
+
'Retrying...',
|
361
|
+
title=_report,
|
362
|
+
frame='half'
|
363
|
+
)
|
364
|
+
|
365
|
+
### Retry.
|
366
|
+
_try_count += 1
|
367
|
+
result = wrap_retry(
|
368
|
+
func,
|
369
|
+
*args,
|
370
|
+
_report=_report,
|
371
|
+
_exception=_exception,
|
372
|
+
_try_total=_try_total,
|
373
|
+
_try_count=_try_count,
|
374
|
+
**kwargs
|
375
|
+
)
|
376
|
+
|
377
|
+
# Try count full.
|
378
|
+
else:
|
379
|
+
result = func(*args, **kwargs)
|
380
|
+
|
381
|
+
return result
|
382
|
+
|
383
|
+
|
384
|
+
@overload
|
385
|
+
def wrap_dos_command(
|
386
|
+
func: Callable,
|
387
|
+
*args: Any,
|
388
|
+
**kwargs: Any
|
389
|
+
) -> Any: ...
|
390
|
+
|
391
|
+
@wrap_frame
|
392
|
+
def wrap_dos_command(
|
393
|
+
func: Callable,
|
394
|
+
*args: Any,
|
395
|
+
**kwargs: Any
|
396
|
+
) -> Any:
|
397
|
+
"""
|
398
|
+
Decorator, use DOS command to input arguments to function.
|
399
|
+
Use DOS command `python file --help` to view help information.
|
400
|
+
|
401
|
+
Parameters
|
402
|
+
----------
|
403
|
+
func : Function to be decorated.
|
404
|
+
args : Position arguments of decorated function.
|
405
|
+
kwargs : Keyword arguments of decorated function.
|
406
|
+
|
407
|
+
Returns
|
408
|
+
-------
|
409
|
+
Function execution result.
|
410
|
+
"""
|
411
|
+
|
412
|
+
# Get parameter.
|
413
|
+
arg_info = get_arg_info(func)
|
414
|
+
|
415
|
+
# Set DOS command.
|
416
|
+
usage = getdoc(func)
|
417
|
+
if usage is not None:
|
418
|
+
usage = 'input arguments to function "%s"\n\n%s' % (func.__name__, usage)
|
419
|
+
parser = ArgumentParser(usage=usage)
|
420
|
+
for info in arg_info:
|
421
|
+
annotation_text = str(info['annotation'])
|
422
|
+
if info['annotation'] is None:
|
423
|
+
arg_type = str
|
424
|
+
arg_help = None
|
425
|
+
else:
|
426
|
+
if 'str' in annotation_text:
|
427
|
+
arg_type = str
|
428
|
+
elif 'float' in annotation_text:
|
429
|
+
arg_type = float
|
430
|
+
elif 'int' in annotation_text:
|
431
|
+
arg_type = int
|
432
|
+
elif 'bool' in annotation_text:
|
433
|
+
arg_type = bool
|
434
|
+
else:
|
435
|
+
arg_type = str
|
436
|
+
arg_help = annotation_text
|
437
|
+
if info['type'] in ('var_position', 'var_position'):
|
438
|
+
parser.add_argument(
|
439
|
+
info['name'],
|
440
|
+
nargs='*',
|
441
|
+
type=arg_type,
|
442
|
+
help=arg_help
|
443
|
+
)
|
444
|
+
else:
|
445
|
+
parser.add_argument(
|
446
|
+
info['name'],
|
447
|
+
nargs='?',
|
448
|
+
type=arg_type,
|
449
|
+
help=arg_help
|
450
|
+
)
|
451
|
+
kw_name = '--' + info['name']
|
452
|
+
parser.add_argument(
|
453
|
+
kw_name,
|
454
|
+
nargs='*',
|
455
|
+
type=arg_type,
|
456
|
+
help=arg_help,
|
457
|
+
metavar='value',
|
458
|
+
dest=kw_name
|
459
|
+
)
|
460
|
+
|
461
|
+
# Get argument.
|
462
|
+
namespace = parser.parse_args()
|
463
|
+
command_args = []
|
464
|
+
command_kwargs = {}
|
465
|
+
for info in arg_info:
|
466
|
+
|
467
|
+
## Position argument.
|
468
|
+
value = getattr(namespace, info['name'])
|
469
|
+
if value is not None:
|
470
|
+
if value.__class__ == list:
|
471
|
+
command_args.extend(value)
|
472
|
+
else:
|
473
|
+
command_args.append(value)
|
474
|
+
|
475
|
+
## Keyword argument.
|
476
|
+
if info['type'] not in ('var_position', 'var_position'):
|
477
|
+
kw_name = '--' + info['name']
|
478
|
+
kw_value = getattr(namespace, kw_name)
|
479
|
+
if kw_value.__class__ == list:
|
480
|
+
kw_value_len = len(kw_value)
|
481
|
+
match kw_value_len:
|
482
|
+
case 0:
|
483
|
+
kw_value = None
|
484
|
+
case 1:
|
485
|
+
kw_value = kw_value[0]
|
486
|
+
command_kwargs[info['name']] = kw_value
|
487
|
+
|
488
|
+
# Execute function.
|
489
|
+
if command_args == []:
|
490
|
+
func_args = args
|
491
|
+
else:
|
492
|
+
func_args = command_args
|
493
|
+
func_kwargs = {
|
494
|
+
**kwargs,
|
495
|
+
**command_kwargs
|
496
|
+
}
|
497
|
+
result = func(
|
498
|
+
*func_args,
|
499
|
+
**func_kwargs
|
500
|
+
)
|
501
|
+
|
502
|
+
return result
|
503
|
+
|
504
|
+
|
505
|
+
# Cache decorator data.
|
506
|
+
wrap_cache_data: dict[Callable, list[tuple[Any, Any, Any]]] = {}
|
507
|
+
|
508
|
+
|
509
|
+
@overload
|
510
|
+
def wrap_cache(
|
511
|
+
func: Callable,
|
512
|
+
*args: Any,
|
513
|
+
_overwrite: bool = False,
|
514
|
+
**kwargs: Any
|
515
|
+
) -> Any: ...
|
516
|
+
|
517
|
+
@wrap_frame
|
518
|
+
def wrap_cache(
|
519
|
+
func: Callable,
|
520
|
+
*args: Any,
|
521
|
+
_overwrite: bool = False,
|
522
|
+
**kwargs: Any
|
523
|
+
) -> Any:
|
524
|
+
"""
|
525
|
+
Decorator, Cache the return result of function input.
|
526
|
+
if no cache, cache it.
|
527
|
+
if cached, skip execution and return result.
|
528
|
+
|
529
|
+
Parameters
|
530
|
+
----------
|
531
|
+
func : Function to be decorated.
|
532
|
+
args : Position arguments of decorated function.
|
533
|
+
_overwrite : Whether to overwrite cache.
|
534
|
+
kwargs : Keyword arguments of decorated function.
|
535
|
+
|
536
|
+
Returns
|
537
|
+
-------
|
538
|
+
Function execution result.
|
539
|
+
"""
|
540
|
+
|
541
|
+
# Index.
|
542
|
+
wrap_cache_data_func = wrap_cache_data.setdefault(func, [])
|
543
|
+
cache_index = None
|
544
|
+
for index, (cache_args, cache_kwargs, cache_result) in enumerate(wrap_cache_data_func):
|
545
|
+
if (
|
546
|
+
cache_args == args
|
547
|
+
and cache_kwargs == kwargs
|
548
|
+
):
|
549
|
+
if _overwrite:
|
550
|
+
cache_index = index
|
551
|
+
break
|
552
|
+
else:
|
553
|
+
return cache_result
|
554
|
+
|
555
|
+
# Execute.
|
556
|
+
result = func(*args, **kwargs)
|
557
|
+
|
558
|
+
# Cache.
|
559
|
+
data = (args, kwargs, result)
|
560
|
+
if cache_index is None:
|
561
|
+
wrap_cache_data_func.append(data)
|
562
|
+
else:
|
563
|
+
wrap_cache_data_func[cache_index] = data
|
564
|
+
|
565
|
+
return result
|
566
|
+
|
567
|
+
|
568
|
+
@overload
|
569
|
+
def wrap_redirect_stdout(
|
570
|
+
func: Callable,
|
571
|
+
*args: Any,
|
572
|
+
_redirect: Optional[Union[list, IOBase]] = None,
|
573
|
+
**kwargs: Any
|
574
|
+
) -> Any: ...
|
575
|
+
|
576
|
+
@wrap_frame
|
577
|
+
def wrap_redirect_stdout(
|
578
|
+
func: Callable,
|
579
|
+
*args: Any,
|
580
|
+
_redirect: Optional[Union[list, IOBase]] = None,
|
581
|
+
**kwargs: Any
|
582
|
+
) -> Any:
|
583
|
+
"""
|
584
|
+
Redirect standard output.
|
585
|
+
|
586
|
+
Parameters
|
587
|
+
----------
|
588
|
+
func : Function to be decorated.
|
589
|
+
args : Position arguments of decorated function.
|
590
|
+
_redirect : Redirect output list or IO object.
|
591
|
+
kwargs : Keyword arguments of decorated function.
|
592
|
+
|
593
|
+
Returns
|
594
|
+
-------
|
595
|
+
Function execution result.
|
596
|
+
"""
|
597
|
+
|
598
|
+
# Get parameter.
|
599
|
+
if isinstance(_redirect, IOBase):
|
600
|
+
str_io = _redirect
|
601
|
+
else:
|
602
|
+
str_io = StringIO()
|
603
|
+
|
604
|
+
# Execute.
|
605
|
+
with redirect_stdout(str_io):
|
606
|
+
result = func(*args, **kwargs)
|
607
|
+
|
608
|
+
# Save.
|
609
|
+
if _redirect.__class__ == list:
|
610
|
+
value = str_io.getvalue()
|
611
|
+
_redirect.append(value)
|
612
|
+
|
613
|
+
return result
|