reykit 1.1.28__py3-none-any.whl → 1.1.30__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/rtext.py CHANGED
@@ -9,25 +9,27 @@
9
9
  """
10
10
 
11
11
 
12
- from typing import Any, Literal
12
+ from typing import Any, Literal, overload
13
13
  from collections.abc import Iterable
14
14
  from decimal import Decimal
15
15
  from pprint import pformat as pprint_pformat
16
16
  from json import dumps as json_dumps
17
17
 
18
- from .rbase import throw
18
+ from .rbase import throw, is_iterable, get_varname
19
19
  from .rmonkey import monkey_patch_pprint_modify_width_judgment
20
+ from .rstdout import get_terminal_size
20
21
 
21
22
 
22
23
  __all__ = (
24
+ 'to_json',
25
+ 'to_text',
23
26
  'split_text',
24
27
  'get_width',
25
28
  'fill_width',
29
+ 'frame_text',
30
+ 'frame_data',
26
31
  'join_data_text',
27
- 'join_filter_text',
28
- 'add_text_frame',
29
- 'to_json',
30
- 'to_text'
32
+ 'join_filter_text'
31
33
  )
32
34
 
33
35
 
@@ -35,14 +37,96 @@ __all__ = (
35
37
  monkey_patch_pprint_modify_width_judgment()
36
38
 
37
39
 
38
- def split_text(text: str, man_len: int, by_width: bool = False) -> list[str]:
40
+ def to_json(
41
+ data: Any,
42
+ compact: bool = True
43
+ ) -> str:
44
+ """
45
+ Convert data to JSON format string.
46
+
47
+ Parameters
48
+ ----------
49
+ data : Data.
50
+ compact : Whether compact content.
51
+
52
+ Returns
53
+ -------
54
+ JSON format string.
55
+ """
56
+
57
+ # Get parameter.
58
+ if compact:
59
+ indent = None
60
+ separators = (',', ':')
61
+ else:
62
+ indent = 4
63
+ separators = None
64
+
65
+ # Convert.
66
+ default = lambda value: (
67
+ value.__float__()
68
+ if type(value) == Decimal
69
+ else repr(value)
70
+ )
71
+ string = json_dumps(
72
+ data,
73
+ ensure_ascii=False,
74
+ indent=indent,
75
+ separators=separators,
76
+ default=default
77
+ )
78
+
79
+ return string
80
+
81
+
82
+ def to_text(
83
+ data: Any,
84
+ width: int | None = None
85
+ ) -> str:
86
+ """
87
+ Format data to text.
88
+
89
+ Parameters
90
+ ----------
91
+ data : Data.
92
+ width : Format width.
93
+ - `None` : Use terminal display character size.
94
+
95
+ Returns
96
+ -------
97
+ Formatted text.
98
+ """
99
+
100
+ # Handle parameter.
101
+ if width is None:
102
+ width, _ = get_terminal_size()
103
+
104
+ # Format.
105
+ match data:
106
+
107
+ ## Replace tab.
108
+ case str():
109
+ text = data.replace('\t', ' ')
110
+
111
+ ## Format contents.
112
+ case list() | tuple() | dict() | set():
113
+ text = pprint_pformat(data, width=width, sort_dicts=False)
114
+
115
+ ## Other.
116
+ case _:
117
+ text = str(data)
118
+
119
+ return text
120
+
121
+
122
+ def split_text(text: str, max_len: int, by_width: bool = False) -> list[str]:
39
123
  """
40
124
  Split text by max length or not greater than display width.
41
125
 
42
126
  Parameters
43
127
  ----------
44
128
  text : Text.
45
- man_len : max length.
129
+ max_len : max length.
46
130
  by_width : Whether by char displayed width count length.
47
131
 
48
132
  Returns
@@ -60,7 +144,7 @@ def split_text(text: str, man_len: int, by_width: bool = False) -> list[str]:
60
144
  for char in text:
61
145
  char_width = get_width(char)
62
146
  str_width += char_width
63
- if str_width > man_len:
147
+ if str_width > max_len:
64
148
  string = ''.join(str_group)
65
149
  texts.append(string)
66
150
  str_group = [char]
@@ -73,12 +157,12 @@ def split_text(text: str, man_len: int, by_width: bool = False) -> list[str]:
73
157
  ## By char number.
74
158
  else:
75
159
  test_len = len(text)
76
- split_n = test_len // man_len
77
- if test_len % man_len:
160
+ split_n = test_len // max_len
161
+ if test_len % max_len:
78
162
  split_n += 1
79
163
  for n in range(split_n):
80
- start_indxe = man_len * n
81
- end_index = man_len * (n + 1)
164
+ start_indxe = max_len * n
165
+ end_index = max_len * (n + 1)
82
166
  text_group = text[start_indxe:end_index]
83
167
  texts.append(text_group)
84
168
 
@@ -204,6 +288,213 @@ def fill_width(text: str, char: str, width: int, align: Literal['left', 'right',
204
288
  return new_text
205
289
 
206
290
 
291
+ @overload
292
+ def frame_text(
293
+ *texts: Iterable[str],
294
+ title: str | Iterable[str] | None = None,
295
+ width: int | None = None,
296
+ frame: Literal['top', 'box'] = 'box',
297
+ border: Literal['ascii', 'thick', 'double'] = 'double'
298
+ ) -> str: ...
299
+
300
+ @overload
301
+ def frame_text(
302
+ *texts: Iterable[str],
303
+ width: int | None = None,
304
+ frame: Literal['left'],
305
+ border: Literal['ascii', 'thick', 'double'] = 'double'
306
+ ) -> str: ...
307
+
308
+ def frame_text(
309
+ *texts: Iterable[str],
310
+ title: str | Iterable[str] | None = None,
311
+ width: int | None = None,
312
+ frame: Literal['left', 'top', 'box'] = 'box',
313
+ border: Literal['ascii', 'thick', 'double'] = 'double'
314
+ ) -> str:
315
+ """
316
+ Frame text.
317
+
318
+ Parameters
319
+ ----------
320
+ texts : Texts.
321
+ title : Frame title.
322
+ - `None`: No title.
323
+ - `str` : Use this value.
324
+ - `Iterable[str]` : Connect this values and use.
325
+ width : Frame width.
326
+ - `None` : Use terminal display character size.
327
+ frame : Frame type.
328
+ - `Literal[`left`]`: Line beginning add character column.
329
+ - `Literal[`top`]`: Line head add character line, with title.
330
+ - `Literal[`box`]`: Add four borders, with title, automatic newline.
331
+ border : Border type.
332
+ - `Literal['ascii']`: Use ASCII character.
333
+ - `Literal['thick']`: Use thick line character.
334
+ - `Literal['double']`: Use double line character.
335
+
336
+ Returns
337
+ -------
338
+ Added frame text.
339
+ """
340
+
341
+ # Handle parameter.
342
+ if width is None:
343
+ width, _ = get_terminal_size()
344
+ line_chars_dict = {
345
+ 'double': '║═╔╗╚╝╡│╞╟─╢╓╙╒╕╶╴',
346
+ 'thick': '┃━┏┓┗┛┥│┝┠─┨┎┖┍┑╶╴',
347
+ 'ascii': '|-++++|||+-+/\\/\\ '
348
+ }
349
+ (
350
+ char_v,
351
+ char_h,
352
+ char_to_l,
353
+ char_to_r,
354
+ char_bo_l,
355
+ char_bo_r,
356
+ char_ti_l,
357
+ char_ti_c,
358
+ char_ti_r,
359
+ char_sp_l,
360
+ char_sp_c,
361
+ char_sp_r,
362
+ char_le_t_e,
363
+ char_le_b_e,
364
+ char_to_l_e,
365
+ char_to_r_e,
366
+ char_sp_l_e,
367
+ char_sp_r_e
368
+ ) = line_chars_dict[border]
369
+ if frame == 'top':
370
+ char_v = ' '
371
+ char_to_l = char_to_l_e
372
+ char_to_r = char_to_r_e
373
+ char_sp_l = char_sp_l_e
374
+ char_sp_r = char_sp_r_e
375
+
376
+ # Lines.
377
+ parts = []
378
+
379
+ ## Top.
380
+ match frame:
381
+ case 'left':
382
+ part_top = char_le_t_e
383
+ case 'top' | 'box':
384
+ if is_iterable(title, (str,)):
385
+ title = f' {char_ti_c} '.join(title)
386
+ if (
387
+ title is not None
388
+ and len(title) > width - 4
389
+ ):
390
+ title = None
391
+ if title is None:
392
+ part_top = char_h * (width - 2)
393
+ else:
394
+ part_top = f'{char_ti_l} {title} {char_ti_r}'
395
+ part_top = fill_width(part_top, char_h, width - 2, 'center')
396
+ part_top = f'{char_to_l}{part_top}{char_to_r}'
397
+ parts.append(part_top)
398
+
399
+ ## Content.
400
+ match frame:
401
+ case 'left':
402
+ char_v_l = char_v
403
+ char_v_r = ''
404
+ width_content = width - 1
405
+ line_split = char_sp_l
406
+ case 'top' | 'box':
407
+ char_v_l = char_v_r = char_v
408
+ width_content = width - 2
409
+ line_split = f'{char_sp_l}{char_sp_c * (width - 2)}{char_sp_r}'
410
+ part_content = f'\n{line_split}\n'.join(
411
+ [
412
+ '\n'.join(
413
+ [
414
+ f'{char_v_l}{fill_width(text_line_width, ' ', width_content)}{char_v_r}'
415
+ for text_line in text.split('\n')
416
+ for text_line_width in split_text(text_line, width_content, True)
417
+ ]
418
+ )
419
+ for text in texts
420
+ ]
421
+ )
422
+ parts.append(part_content)
423
+
424
+ ## Bottom.
425
+ match frame:
426
+ case 'left':
427
+ parts.append(char_le_b_e)
428
+ case 'top':
429
+ pass
430
+ case 'box':
431
+ part_bottom = f'{char_bo_l}{char_h * (width - 2)}{char_bo_r}'
432
+ parts.append(part_bottom)
433
+
434
+ # Join.
435
+ result = '\n'.join(parts)
436
+ return result
437
+
438
+
439
+ def frame_data(
440
+ *data: Any,
441
+ title: str | Iterable[str] | None = None,
442
+ width: int | None = None,
443
+ frame: Literal['left', 'top', 'box'] = 'box',
444
+ border: Literal['ascii', 'thick', 'double'] = 'double'
445
+ ) -> str:
446
+ """
447
+ Frame text.
448
+
449
+ Parameters
450
+ ----------
451
+ data : Data.
452
+ title : Frame title.
453
+ - `None`: Use variable name of argument `data`.
454
+ - `str` : Use this value.
455
+ - `Iterable[str]` : Connect this values and use.
456
+ width : Frame width.
457
+ - `None` : Use terminal display character size.
458
+ frame : Frame type.
459
+ - `Literal[`left`]`: Line beginning add character column.
460
+ - `Literal[`top`]`: Line head add character line, with title.
461
+ - `Literal[`box`]`: Add four borders, with title, automatic newline.
462
+ border : Border type.
463
+ - `Literal['ascii']`: Use ASCII character.
464
+ - `Literal['thick']`: Use thick line character.
465
+ - `Literal['double']`: Use double line character.
466
+
467
+ Returns
468
+ -------
469
+ Added frame text.
470
+ """
471
+
472
+ # handle parameter.
473
+ if title is None:
474
+ title: list[str] = get_varname('data')
475
+ if width is None:
476
+ width, _ = get_terminal_size()
477
+ if frame == 'left':
478
+ width_text = width - 1
479
+ else:
480
+ width_text = width - 2
481
+ texts = [
482
+ to_text(elem, width_text)
483
+ for elem in data
484
+ ]
485
+
486
+ # Frame.
487
+ text = frame_text(
488
+ *texts,
489
+ title=title,
490
+ width=width,
491
+ frame=frame,
492
+ border=border
493
+ )
494
+
495
+ return text
496
+
497
+
207
498
  def join_data_text(data: Iterable) -> str:
208
499
  """
209
500
  Join data to text.
@@ -237,8 +528,8 @@ def join_data_text(data: Iterable) -> str:
237
528
  else:
238
529
  text = '\n'.join(
239
530
  [
240
- str(element)
241
- for element in data
531
+ str(elem)
532
+ for elem in data
242
533
  ]
243
534
  )
244
535
 
@@ -264,194 +555,12 @@ def join_filter_text(data: Iterable, char: str = ',', filter_: tuple = (None, ''
264
555
 
265
556
  # Filter and convert.
266
557
  data = [
267
- str(element)
268
- for element in data
269
- if element not in filter_
558
+ str(elem)
559
+ for elem in data
560
+ if elem not in filter_
270
561
  ]
271
562
 
272
563
  # Join.
273
564
  text = char.join(data)
274
565
 
275
566
  return text
276
-
277
-
278
- def add_text_frame(
279
- *texts: str,
280
- title: str | None,
281
- width: int,
282
- frame: Literal['full', 'half', 'top', 'half_plain', 'top_plain']
283
- ) -> str:
284
- """
285
- Add text frame.
286
-
287
- Parameters
288
- ----------
289
- texts : Texts.
290
- title : Frame title.
291
- - `None | Literal['']`: No title.
292
- - `str`: Use this value as the title.
293
- width : Frame width.
294
- frame : Frame type.
295
- - `Literal[`full`]`: Add beautiful four side frame and limit length.
296
- When throw `exception`, then frame is `half` type.
297
- - `Literal[`half`]`: Add beautiful top and bottom side frame.
298
- - `Literal[`top`]`: Add beautiful top side frame.
299
- - `Literal[`half_plain`]`: Add plain top and bottom side frame.
300
- - `Literal[`top_plain`]`: Add plain top side frame.
301
-
302
- Returns
303
- -------
304
- Added frame text.
305
- """
306
-
307
- # Handle parameter.
308
- if title is None or len(title) > width - 6:
309
- title = ''
310
-
311
- # Generate frame.
312
- match frame:
313
-
314
- ## Full type.
315
- case 'full':
316
- if title != '':
317
- title = f'╡ {title} ╞'
318
- width_in = width - 2
319
- _contents = []
320
- try:
321
- for content in texts:
322
- content_str = str(content)
323
- pieces_str = content_str.split('\n')
324
- content_str = [
325
- '║%s║' % fill_width(line_str, ' ', width_in)
326
- for piece_str in pieces_str
327
- for line_str in split_text(piece_str, width_in, True)
328
- ]
329
- content = '\n'.join(content_str)
330
- _contents.append(content)
331
- except:
332
- frame_top = fill_width(title, '═', width, 'center')
333
- frame_split = '─' * width
334
- frame_bottom = '═' * width
335
- _contents = texts
336
- else:
337
- frame_top = '╔%s╗' % fill_width(title, '═', width_in, 'center')
338
- frame_split = '╟%s╢' % ('─' * width_in)
339
- frame_bottom = '╚%s╝' % ('═' * width_in)
340
-
341
- ## Half type.
342
- case 'half' | 'top':
343
- if title != '':
344
- title = f'╡ {title} ╞'
345
- frame_top = fill_width(title, '═', width, 'center')
346
- frame_split = '─' * width
347
- match frame:
348
- case 'half':
349
- frame_bottom = '═' * width
350
- case 'top':
351
- frame_bottom = None
352
- _contents = texts
353
-
354
- ## Plain type.
355
- case 'half_plain' | 'top_plain':
356
- if title != '':
357
- title = f'| {title} |'
358
- frame_top = fill_width(title, '=', width, 'center')
359
- frame_split = '-' * width
360
- match frame:
361
- case 'half_plain':
362
- frame_bottom = '=' * width
363
- case 'top_plain':
364
- frame_bottom = None
365
- _contents = texts
366
-
367
- ## Throw exception.
368
- case _:
369
- throw(ValueError, frame)
370
-
371
- # Join.
372
- texts = [frame_top]
373
- for index, content in enumerate(_contents):
374
- if index != 0:
375
- texts.append(frame_split)
376
- texts.append(content)
377
- texts.append(frame_bottom)
378
- text = join_filter_text(texts, '\n')
379
-
380
- return text
381
-
382
-
383
- def to_json(
384
- data: Any,
385
- compact: bool = True
386
- ) -> str:
387
- """
388
- Convert data to JSON format string.
389
-
390
- Parameters
391
- ----------
392
- data : Data.
393
- compact : Whether compact content.
394
-
395
- Returns
396
- -------
397
- JSON format string.
398
- """
399
-
400
- # Get parameter.
401
- if compact:
402
- indent = None
403
- separators = (',', ':')
404
- else:
405
- indent = 4
406
- separators = None
407
-
408
- # Convert.
409
- default = lambda value: (
410
- value.__float__()
411
- if type(value) == Decimal
412
- else repr(value)
413
- )
414
- string = json_dumps(
415
- data,
416
- ensure_ascii=False,
417
- indent=indent,
418
- separators=separators,
419
- default=default
420
- )
421
-
422
- return string
423
-
424
-
425
- def to_text(
426
- data: Any,
427
- width: int = 100
428
- ) -> str:
429
- """
430
- Format data to text.
431
-
432
- Parameters
433
- ----------
434
- data : Data.
435
- width : Format width.
436
-
437
- Returns
438
- -------
439
- Formatted text.
440
- """
441
-
442
- # Format.
443
- match data:
444
-
445
- ## Replace tab.
446
- case str():
447
- text = data.replace('\t', ' ')
448
-
449
- ## Format contents.
450
- case list() | tuple() | dict() | set():
451
- text = pprint_pformat(data, width=width, sort_dicts=False)
452
-
453
- ## Other.
454
- case _:
455
- text = str(data)
456
-
457
- return text
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: reykit
3
- Version: 1.1.28
3
+ Version: 1.1.30
4
4
  Summary: Kit method set.
5
5
  Project-URL: homepage, https://github.com/reyxbo/reykit/
6
6
  Author-email: Rey <reyxbo@163.com>
@@ -1,28 +1,28 @@
1
1
  reykit/__init__.py,sha256=V86CHqPAAVkooVx3_QIOKpDIFVneQCTTSwfJ-uWgBno,788
2
2
  reykit/rall.py,sha256=7Hip02YOkIDm3_xkoSDjvvYV2LhdBV2r4UKzWWnIfIo,628
3
- reykit/rbase.py,sha256=npUa3FMfcFF422fZDElFoZrjDESFgW9mzZrNbuWZu-w,22512
4
- reykit/rdata.py,sha256=RDrDWcNLIVEznNqT27155eLqdQLsp9rp6gxYbopI5yg,10138
3
+ reykit/rbase.py,sha256=MluWXVrai98DMlhNrYLvpEZkxl4F683cRBHS8osKiGw,22306
4
+ reykit/rdata.py,sha256=COe2VVGaUV0L1MD6PB7zL8treVNehVFqJELbm7wAvs0,9471
5
5
  reykit/remail.py,sha256=s7TXbLgEWEqNoeM42c6FpPufB2LajHgQuahfZri3urQ,6706
6
6
  reykit/rimage.py,sha256=p7caatLE71yy7GUTkTKyMOaJTeBfl6pZr_7BFjcDvY8,6159
7
7
  reykit/rlog.py,sha256=JgxLeMEl2UBwZG5IiGr-Cr_NPfkkkc2Yebb6tgH1zLQ,25525
8
- reykit/rmonkey.py,sha256=ZTHsXI3T81WE0rlfVUhf6N5SYoxPbsgVImAasFJqnKU,8315
8
+ reykit/rmonkey.py,sha256=tnluHGe_a_NGin1zxy-COzwhJknKvChHyh3J9eu_4ns,8309
9
9
  reykit/rnet.py,sha256=uS27Ownt9ELsjVKpGMPVN1Endc9s7z7CfIBkfE8bPMs,15033
10
10
  reykit/rnum.py,sha256=PhG4V_BkVfCJUsbpMDN1umGZly1Hsus80TW8bpyBtyY,3653
11
- reykit/ros.py,sha256=GZBhU_Ni1W5EqjLoS0mYWUk5-I7lmhg6b4sv3WvkDoA,40855
11
+ reykit/ros.py,sha256=416gOKHhy3jWur-KDq5VsHNeKQtZ87jO2HSxUeu6as4,40865
12
12
  reykit/rrand.py,sha256=9QPXCsREIu45g6WP-XN67X05kmW3cTmctn3InvqYxuY,8947
13
13
  reykit/rre.py,sha256=4DVxy28dl5zn6_II8-cgr7E2nVPH5QJIJVB4o7Vsf1A,6078
14
14
  reykit/rschedule.py,sha256=_nrfrXYxlFAKCDbM8ibTTb60zNDlHxyE310cv-A19Kw,5799
15
- reykit/rstdout.py,sha256=U9so0RGyiJrv1lhCA392XbzxIOnT4XZUrWQ_kuPjlAk,9840
16
- reykit/rsys.py,sha256=-1MYplwvp9HOrTiNU6eS1FW8vCnpt-iXbYxhR0yPQCE,24894
15
+ reykit/rstdout.py,sha256=_FL2-l-auGPWmpL00R_DNw2eFFn19mF7hCq3jCVgomI,8179
16
+ reykit/rsys.py,sha256=8Q9ZdggxRHXHMOwjMQa_kBN3gTkmpduHoXrKfa5UXqs,24933
17
17
  reykit/rtable.py,sha256=MYEkm-PvYyNgCy1cHodNF4JgJNg1pzTy6NtYfF6CHRs,12001
18
18
  reykit/rtask.py,sha256=FPRBKVIzuH5PUR9XyY3J9YF8rXDpIMWySXLc3y6zAwk,22812
19
- reykit/rtext.py,sha256=l8yRxaWmDxdPLkXfQufUGjXSRMbmKfbYkkiihtvNixQ,11048
19
+ reykit/rtext.py,sha256=aMbnLLh08kRlYOT4rK55geUlaNkKWIu_lxTaGqhqCRI,13708
20
20
  reykit/rtime.py,sha256=e9I5LieY3DFQq04qzyRT_dwsxc40Dcj9CMDAEmXsGw8,16938
21
21
  reykit/rwrap.py,sha256=RK3wlc2cd-lnAvzqzvKsS21EtCmBNTA3i8HRbaolWE4,15275
22
22
  reykit/rzip.py,sha256=ABUDLwEHQIpcvZbJE_oV78H7dik6nC7kaRz660Ro9Os,3481
23
23
  reykit/rdll/__init__.py,sha256=tdKb-BOKLFn-diCvXjSLg9x71VuRKzkg2KtpOLGLTR4,679
24
24
  reykit/rdll/rdll_core.py,sha256=o6-rKcTQgxZQe0kD3GnwyNb3KL9IogzgCQNOmYLMm7A,5086
25
- reykit-1.1.28.dist-info/METADATA,sha256=TWLwOmgrzneuBFPj_Qx0XU9LuOooqLm5x_3KJoZEhzc,1913
26
- reykit-1.1.28.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
27
- reykit-1.1.28.dist-info/licenses/LICENSE,sha256=UYLPqp7BvPiH8yEZduJqmmyEl6hlM3lKrFIefiD4rvk,1059
28
- reykit-1.1.28.dist-info/RECORD,,
25
+ reykit-1.1.30.dist-info/METADATA,sha256=JWb4r7Ug9idWje8YkEezX8kIIkqH9GjNhgRptrI0VAw,1913
26
+ reykit-1.1.30.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
27
+ reykit-1.1.30.dist-info/licenses/LICENSE,sha256=UYLPqp7BvPiH8yEZduJqmmyEl6hlM3lKrFIefiD4rvk,1059
28
+ reykit-1.1.30.dist-info/RECORD,,