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/rtext.py
ADDED
@@ -0,0 +1,458 @@
|
|
1
|
+
# !/usr/bin/env python
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
|
4
|
+
"""
|
5
|
+
@Time : 2022-12-08 13:18:24
|
6
|
+
@Author : Rey
|
7
|
+
@Contact : reyxbo@163.com
|
8
|
+
@Explain : Text methods.
|
9
|
+
"""
|
10
|
+
|
11
|
+
|
12
|
+
from typing import Any, Literal, Optional
|
13
|
+
from collections.abc import Iterable
|
14
|
+
from decimal import Decimal
|
15
|
+
from pprint import pformat as pprint_pformat
|
16
|
+
from json import dumps as json_dumps
|
17
|
+
|
18
|
+
from .rexception import throw
|
19
|
+
from .rmonkey import monkey_patch_pprint_modify_width_judgment
|
20
|
+
from .rrandom import randi
|
21
|
+
|
22
|
+
|
23
|
+
__all__ = (
|
24
|
+
'split_text',
|
25
|
+
'get_width',
|
26
|
+
'fill_width',
|
27
|
+
'join_data_text',
|
28
|
+
'join_filter_text',
|
29
|
+
'add_text_frame',
|
30
|
+
'to_json',
|
31
|
+
'to_text'
|
32
|
+
)
|
33
|
+
|
34
|
+
|
35
|
+
# Monkey path.
|
36
|
+
monkey_patch_pprint_modify_width_judgment()
|
37
|
+
|
38
|
+
|
39
|
+
def split_text(text: str, man_len: int, by_width: bool = False) -> list[str]:
|
40
|
+
"""
|
41
|
+
Split text by max length or not greater than display width.
|
42
|
+
|
43
|
+
Parameters
|
44
|
+
----------
|
45
|
+
text : Text.
|
46
|
+
man_len : max length.
|
47
|
+
by_width : Whether by char displayed width count length.
|
48
|
+
|
49
|
+
Returns
|
50
|
+
-------
|
51
|
+
Split text.
|
52
|
+
"""
|
53
|
+
|
54
|
+
# Split.
|
55
|
+
texts = []
|
56
|
+
|
57
|
+
## By char displayed width.
|
58
|
+
if by_width:
|
59
|
+
str_group = []
|
60
|
+
str_width = 0
|
61
|
+
for char in text:
|
62
|
+
char_width = get_width(char)
|
63
|
+
str_width += char_width
|
64
|
+
if str_width > man_len:
|
65
|
+
string = ''.join(str_group)
|
66
|
+
texts.append(string)
|
67
|
+
str_group = [char]
|
68
|
+
str_width = char_width
|
69
|
+
else:
|
70
|
+
str_group.append(char)
|
71
|
+
string = ''.join(str_group)
|
72
|
+
texts.append(string)
|
73
|
+
|
74
|
+
## By char number.
|
75
|
+
else:
|
76
|
+
test_len = len(text)
|
77
|
+
split_n = test_len // man_len
|
78
|
+
if test_len % man_len:
|
79
|
+
split_n += 1
|
80
|
+
for n in range(split_n):
|
81
|
+
start_indxe = man_len * n
|
82
|
+
end_index = man_len * (n + 1)
|
83
|
+
text_group = text[start_indxe:end_index]
|
84
|
+
texts.append(text_group)
|
85
|
+
|
86
|
+
return texts
|
87
|
+
|
88
|
+
|
89
|
+
def get_width(text: str) -> int:
|
90
|
+
"""
|
91
|
+
Get text display width.
|
92
|
+
|
93
|
+
Parameters
|
94
|
+
----------
|
95
|
+
text : Text.
|
96
|
+
|
97
|
+
Returns
|
98
|
+
-------
|
99
|
+
Text display width.
|
100
|
+
"""
|
101
|
+
|
102
|
+
# Set parameter.
|
103
|
+
widths = (
|
104
|
+
(126, 1),
|
105
|
+
(159, 0),
|
106
|
+
(687, 1),
|
107
|
+
(710, 0),
|
108
|
+
(711, 1),
|
109
|
+
(727, 0),
|
110
|
+
(733, 1),
|
111
|
+
(879, 0),
|
112
|
+
(1154, 1),
|
113
|
+
(1161, 0),
|
114
|
+
(4347, 1),
|
115
|
+
(4447, 2),
|
116
|
+
(7467, 1),
|
117
|
+
(7521, 0),
|
118
|
+
(8369, 1),
|
119
|
+
(8426, 0),
|
120
|
+
(9000, 1),
|
121
|
+
(9002, 2),
|
122
|
+
(11021, 1),
|
123
|
+
(12350, 2),
|
124
|
+
(12351, 1),
|
125
|
+
(12438, 2),
|
126
|
+
(12442, 0),
|
127
|
+
(19893, 2),
|
128
|
+
(19967, 1),
|
129
|
+
(55203, 2),
|
130
|
+
(63743, 1),
|
131
|
+
(64106, 2),
|
132
|
+
(65039, 1),
|
133
|
+
(65059, 0),
|
134
|
+
(65131, 2),
|
135
|
+
(65279, 1),
|
136
|
+
(65376, 2),
|
137
|
+
(65500, 1),
|
138
|
+
(65510, 2),
|
139
|
+
(120831, 1),
|
140
|
+
(262141, 2),
|
141
|
+
(1114109, 1)
|
142
|
+
)
|
143
|
+
|
144
|
+
# Get width.
|
145
|
+
total_width = 0
|
146
|
+
for char in text:
|
147
|
+
char_unicode = ord(char)
|
148
|
+
if (
|
149
|
+
char_unicode == 0xe
|
150
|
+
or char_unicode == 0xf
|
151
|
+
):
|
152
|
+
char_width = 0
|
153
|
+
else:
|
154
|
+
char_width = 1
|
155
|
+
for num, wid in widths:
|
156
|
+
if char_unicode <= num:
|
157
|
+
char_width = wid
|
158
|
+
break
|
159
|
+
total_width += char_width
|
160
|
+
|
161
|
+
return total_width
|
162
|
+
|
163
|
+
|
164
|
+
def fill_width(text: str, char: str, width: int, align: Literal['left', 'right', 'center'] = 'right') -> str:
|
165
|
+
"""
|
166
|
+
Text fill character by display width.
|
167
|
+
|
168
|
+
Parameters
|
169
|
+
----------
|
170
|
+
text : Fill text.
|
171
|
+
char : Fill character.
|
172
|
+
width : Fill width.
|
173
|
+
align : Align orientation.
|
174
|
+
- `Literal[`left`]`: Fill right, align left.
|
175
|
+
- `Literal[`right`]`: Fill left, align right.
|
176
|
+
- `Literal[`center`]`: Fill both sides, align center.
|
177
|
+
|
178
|
+
Returns
|
179
|
+
-------
|
180
|
+
Text after fill.
|
181
|
+
"""
|
182
|
+
|
183
|
+
# Check parameter.
|
184
|
+
if get_width(char) != 1:
|
185
|
+
throw(ValueError, char)
|
186
|
+
|
187
|
+
# Fill width.
|
188
|
+
text_width = get_width(text)
|
189
|
+
fill_width = width - text_width
|
190
|
+
if fill_width > 0:
|
191
|
+
match align:
|
192
|
+
case 'left':
|
193
|
+
new_text = ''.join((char * fill_width, text))
|
194
|
+
case 'right':
|
195
|
+
new_text = ''.join((text, char * fill_width))
|
196
|
+
case 'center':
|
197
|
+
fill_width_left = int(fill_width / 2)
|
198
|
+
fill_width_right = fill_width - fill_width_left
|
199
|
+
new_text = ''.join((char * fill_width_left, text, char * fill_width_right))
|
200
|
+
case _:
|
201
|
+
throw(ValueError, align)
|
202
|
+
else:
|
203
|
+
new_text = text
|
204
|
+
|
205
|
+
return new_text
|
206
|
+
|
207
|
+
|
208
|
+
def join_data_text(data: Iterable) -> str:
|
209
|
+
"""
|
210
|
+
Join data to text.
|
211
|
+
|
212
|
+
Parameters
|
213
|
+
----------
|
214
|
+
data : Data.
|
215
|
+
|
216
|
+
Returns
|
217
|
+
-------
|
218
|
+
Joined text.
|
219
|
+
"""
|
220
|
+
|
221
|
+
# Join.
|
222
|
+
|
223
|
+
## dict type.
|
224
|
+
if data.__class__ == dict:
|
225
|
+
texts = []
|
226
|
+
for key, value in data.items():
|
227
|
+
key_str = str(key)
|
228
|
+
value_str = str(value)
|
229
|
+
if '\n' in value_str:
|
230
|
+
value_str = value_str.replace('\n', '\n ')
|
231
|
+
text_part = f'{key_str}:\n {value_str}'
|
232
|
+
else:
|
233
|
+
text_part = f'{key_str}: {value_str}'
|
234
|
+
texts.append(text_part)
|
235
|
+
text = '\n'.join(texts)
|
236
|
+
|
237
|
+
## Other type.
|
238
|
+
else:
|
239
|
+
text = '\n'.join(
|
240
|
+
[
|
241
|
+
str(element)
|
242
|
+
for element in data
|
243
|
+
]
|
244
|
+
)
|
245
|
+
|
246
|
+
return text
|
247
|
+
|
248
|
+
|
249
|
+
def join_filter_text(data: Iterable, char: str = ',', filter_: tuple = (None, '')) -> str:
|
250
|
+
"""
|
251
|
+
Join and filter text.
|
252
|
+
|
253
|
+
Parameters
|
254
|
+
----------
|
255
|
+
data : Data.
|
256
|
+
- `Element is 'str'`: Join.
|
257
|
+
- `Element is 'Any'`: Convert to string and join.
|
258
|
+
char : Join character.
|
259
|
+
filter_ : Filter elements.
|
260
|
+
|
261
|
+
Returns
|
262
|
+
-------
|
263
|
+
Joined text.
|
264
|
+
"""
|
265
|
+
|
266
|
+
# Filter and convert.
|
267
|
+
data = [
|
268
|
+
str(element)
|
269
|
+
for element in data
|
270
|
+
if element not in filter_
|
271
|
+
]
|
272
|
+
|
273
|
+
# Join.
|
274
|
+
text = char.join(data)
|
275
|
+
|
276
|
+
return text
|
277
|
+
|
278
|
+
|
279
|
+
def add_text_frame(
|
280
|
+
*texts: str,
|
281
|
+
title: Optional[str],
|
282
|
+
width: int,
|
283
|
+
frame: Literal['full', 'half', 'top', 'half_plain', 'top_plain']
|
284
|
+
) -> str:
|
285
|
+
"""
|
286
|
+
Add text frame.
|
287
|
+
|
288
|
+
Parameters
|
289
|
+
----------
|
290
|
+
texts : Texts.
|
291
|
+
title : Frame title.
|
292
|
+
- `Union[None, Literal['']]`: No title.
|
293
|
+
- `str`: Use this value as the title.
|
294
|
+
width : Frame width.
|
295
|
+
frame : Frame type.
|
296
|
+
- `Literal[`full`]`: Add beautiful four side frame and limit length.
|
297
|
+
When throw `exception`, then frame is `half` type.
|
298
|
+
- `Literal[`half`]`: Add beautiful top and bottom side frame.
|
299
|
+
- `Literal[`top`]`: Add beautiful top side frame.
|
300
|
+
- `Literal[`half_plain`]`: Add plain top and bottom side frame.
|
301
|
+
- `Literal[`top_plain`]`: Add plain top side frame.
|
302
|
+
|
303
|
+
Returns
|
304
|
+
-------
|
305
|
+
Added frame text.
|
306
|
+
"""
|
307
|
+
|
308
|
+
# Handle parameter.
|
309
|
+
if title is None or len(title) > width - 6:
|
310
|
+
title = ''
|
311
|
+
|
312
|
+
# Generate frame.
|
313
|
+
match frame:
|
314
|
+
|
315
|
+
## Full type.
|
316
|
+
case 'full':
|
317
|
+
if title != '':
|
318
|
+
title = f'╡ {title} ╞'
|
319
|
+
width_in = width - 2
|
320
|
+
_contents = []
|
321
|
+
try:
|
322
|
+
for content in texts:
|
323
|
+
content_str = str(content)
|
324
|
+
pieces_str = content_str.split('\n')
|
325
|
+
content_str = [
|
326
|
+
'║%s║' % fill_width(line_str, ' ', width_in)
|
327
|
+
for piece_str in pieces_str
|
328
|
+
for line_str in split_text(piece_str, width_in, True)
|
329
|
+
]
|
330
|
+
content = '\n'.join(content_str)
|
331
|
+
_contents.append(content)
|
332
|
+
except:
|
333
|
+
frame_top = fill_width(title, '═', width, 'center')
|
334
|
+
frame_split = '─' * width
|
335
|
+
frame_bottom = '═' * width
|
336
|
+
_contents = texts
|
337
|
+
else:
|
338
|
+
frame_top = '╔%s╗' % fill_width(title, '═', width_in, 'center')
|
339
|
+
frame_split = '╟%s╢' % ('─' * width_in)
|
340
|
+
frame_bottom = '╚%s╝' % ('═' * width_in)
|
341
|
+
|
342
|
+
## Half type.
|
343
|
+
case 'half' | 'top':
|
344
|
+
if title != '':
|
345
|
+
title = f'╡ {title} ╞'
|
346
|
+
frame_top = fill_width(title, '═', width, 'center')
|
347
|
+
frame_split = '─' * width
|
348
|
+
match frame:
|
349
|
+
case 'half':
|
350
|
+
frame_bottom = '═' * width
|
351
|
+
case 'top':
|
352
|
+
frame_bottom = None
|
353
|
+
_contents = texts
|
354
|
+
|
355
|
+
## Plain type.
|
356
|
+
case 'half_plain' | 'top_plain':
|
357
|
+
if title != '':
|
358
|
+
title = f'| {title} |'
|
359
|
+
frame_top = fill_width(title, '=', width, 'center')
|
360
|
+
frame_split = '-' * width
|
361
|
+
match frame:
|
362
|
+
case 'half_plain':
|
363
|
+
frame_bottom = '=' * width
|
364
|
+
case 'top_plain':
|
365
|
+
frame_bottom = None
|
366
|
+
_contents = texts
|
367
|
+
|
368
|
+
## Throw exception.
|
369
|
+
case _:
|
370
|
+
throw(ValueError, frame)
|
371
|
+
|
372
|
+
# Join.
|
373
|
+
texts = [frame_top]
|
374
|
+
for index, content in enumerate(_contents):
|
375
|
+
if index != 0:
|
376
|
+
texts.append(frame_split)
|
377
|
+
texts.append(content)
|
378
|
+
texts.append(frame_bottom)
|
379
|
+
text = join_filter_text(texts, '\n')
|
380
|
+
|
381
|
+
return text
|
382
|
+
|
383
|
+
|
384
|
+
def to_json(
|
385
|
+
data: Any,
|
386
|
+
compact: bool = True
|
387
|
+
) -> str:
|
388
|
+
"""
|
389
|
+
Convert data to JSON format string.
|
390
|
+
|
391
|
+
Parameters
|
392
|
+
----------
|
393
|
+
data : Data.
|
394
|
+
compact : Whether compact content.
|
395
|
+
|
396
|
+
Returns
|
397
|
+
-------
|
398
|
+
JSON format string.
|
399
|
+
"""
|
400
|
+
|
401
|
+
# Get parameter.
|
402
|
+
if compact:
|
403
|
+
indent = None
|
404
|
+
separators = (',', ':')
|
405
|
+
else:
|
406
|
+
indent = 4
|
407
|
+
separators = None
|
408
|
+
|
409
|
+
# Convert.
|
410
|
+
default = lambda value: (
|
411
|
+
value.__float__()
|
412
|
+
if value.__class__ == Decimal
|
413
|
+
else repr(value)
|
414
|
+
)
|
415
|
+
string = json_dumps(
|
416
|
+
data,
|
417
|
+
ensure_ascii=False,
|
418
|
+
indent=indent,
|
419
|
+
separators=separators,
|
420
|
+
default=default
|
421
|
+
)
|
422
|
+
|
423
|
+
return string
|
424
|
+
|
425
|
+
|
426
|
+
def to_text(
|
427
|
+
data: Any,
|
428
|
+
width: int = 100
|
429
|
+
) -> str:
|
430
|
+
"""
|
431
|
+
Format data to text.
|
432
|
+
|
433
|
+
Parameters
|
434
|
+
----------
|
435
|
+
data : Data.
|
436
|
+
width : Format width.
|
437
|
+
|
438
|
+
Returns
|
439
|
+
-------
|
440
|
+
Formatted text.
|
441
|
+
"""
|
442
|
+
|
443
|
+
# Format.
|
444
|
+
match data:
|
445
|
+
|
446
|
+
## Replace tab.
|
447
|
+
case str():
|
448
|
+
text = data.replace('\t', ' ')
|
449
|
+
|
450
|
+
## Format contents.
|
451
|
+
case list() | tuple() | dict() | set():
|
452
|
+
text = pprint_pformat(data, width=width, sort_dicts=False)
|
453
|
+
|
454
|
+
## Other.
|
455
|
+
case _:
|
456
|
+
text = str(data)
|
457
|
+
|
458
|
+
return text
|