absfuyu 2.8.1__py3-none-any.whl → 3.1.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.

Potentially problematic release.


This version of absfuyu might be problematic. Click here for more details.

Files changed (42) hide show
  1. absfuyu/__init__.py +13 -10
  2. absfuyu/__main__.py +55 -38
  3. absfuyu/config/config.json +3 -3
  4. absfuyu/core.py +39 -25
  5. absfuyu/everything.py +4 -5
  6. absfuyu/extensions/__init__.py +3 -2
  7. absfuyu/extensions/dev/__init__.py +162 -19
  8. absfuyu/extensions/dev/password_hash.py +11 -10
  9. absfuyu/extensions/dev/passwordlib.py +256 -0
  10. absfuyu/extensions/dev/pkglib.py +53 -57
  11. absfuyu/extensions/dev/project_starter.py +58 -0
  12. absfuyu/extensions/dev/shutdownizer.py +8 -0
  13. absfuyu/extensions/extra/data_analysis.py +687 -119
  14. absfuyu/fun/__init__.py +88 -118
  15. absfuyu/fun/tarot.py +32 -34
  16. absfuyu/game/tictactoe2.py +90 -78
  17. absfuyu/{collections → general}/__init__.py +14 -12
  18. absfuyu/{collections → general}/content.py +105 -87
  19. absfuyu/{collections → general}/data_extension.py +652 -172
  20. absfuyu/{collections → general}/generator.py +65 -4
  21. absfuyu/{collections → general}/human.py +28 -3
  22. absfuyu/pkg_data/__init__.py +14 -36
  23. absfuyu/pkg_data/chemistry.pkl +0 -0
  24. absfuyu/pkg_data/tarot.pkl +0 -0
  25. absfuyu/tools/converter.py +58 -31
  26. absfuyu/tools/obfuscator.py +4 -4
  27. absfuyu/tools/stats.py +4 -4
  28. absfuyu/tools/web.py +2 -2
  29. absfuyu/util/lunar.py +144 -123
  30. absfuyu/util/path.py +22 -3
  31. absfuyu/util/performance.py +101 -14
  32. absfuyu/version.py +93 -84
  33. {absfuyu-2.8.1.dist-info → absfuyu-3.1.0.dist-info}/METADATA +63 -33
  34. absfuyu-3.1.0.dist-info/RECORD +55 -0
  35. {absfuyu-2.8.1.dist-info → absfuyu-3.1.0.dist-info}/WHEEL +1 -1
  36. absfuyu-3.1.0.dist-info/entry_points.txt +2 -0
  37. absfuyu/pkg_data/chemistry.json +0 -6268
  38. absfuyu/pkg_data/tarot.json +0 -2593
  39. absfuyu-2.8.1.dist-info/RECORD +0 -52
  40. absfuyu-2.8.1.dist-info/entry_points.txt +0 -2
  41. {absfuyu-2.8.1.dist-info → absfuyu-3.1.0.dist-info}/LICENSE +0 -0
  42. {absfuyu-2.8.1.dist-info → absfuyu-3.1.0.dist-info}/top_level.txt +0 -0
@@ -3,23 +3,37 @@ Absfuyu: Data extension
3
3
  -----------------------
4
4
  Extension for data type such as ``list``, ``str``, ``dict``, ...
5
5
 
6
- Version: 1.3.4
7
- Date updated: 24/11/2023 (dd/mm/yyyy)
6
+ Version: 1.12.3
7
+ Date updated: 23/01/2024 (dd/mm/yyyy)
8
8
 
9
9
  Features:
10
10
  ---------
11
11
  - Text
12
- - ListKai
13
- - DictKai
12
+ - ListExt
13
+ - DictExt
14
14
  - IntNumber
15
+
16
+ Usage:
17
+ ------
18
+ >>> from absfuyu.general.data_extension import DictExt, IntNumber, ListExt, Text
15
19
  """
16
20
 
17
21
 
18
22
  # Module level
19
23
  ###########################################################################
20
24
  __all__ = [
21
- "Text", "IntNumber",
22
- "ListKai", "DictKai"
25
+ # Main
26
+ "Text",
27
+ "IntNumber",
28
+ "ListExt",
29
+ "DictExt",
30
+ # Sub
31
+ "Pow",
32
+ "ListREPR",
33
+ "ListNoDunder",
34
+ "DictBoolTrue",
35
+ "DictBoolFalse",
36
+ # "DictNoDunder",
23
37
  ]
24
38
 
25
39
 
@@ -30,19 +44,117 @@ from itertools import accumulate, chain, groupby
30
44
  import math
31
45
  import operator
32
46
  import random
33
- from typing import Any, Dict, List, Optional
47
+ from typing import Any, Callable, Dict, List, Optional, Tuple, Union
48
+ from sys import version_info as python_version
34
49
 
35
- from absfuyu.collections.generator import Generator, Charset
36
- from absfuyu.logger import logger
50
+ from absfuyu.general.generator import Generator, Charset
51
+ from absfuyu.logger import logger, _compress_list_for_print
37
52
  from absfuyu.util import set_min, set_min_max
38
53
 
39
54
 
55
+ # Function
56
+ ###########################################################################
57
+ def _dict_bool(dict_object: dict, option: bool) -> Optional[dict]:
58
+ """
59
+ Support function DictBool class
60
+ """
61
+ out = dict()
62
+ for k, v in dict_object.items():
63
+ if v == option:
64
+ out[k] = v
65
+ if out:
66
+ return out
67
+ else:
68
+ return None
69
+
70
+
71
+ # Sub class
72
+ ###########################################################################
73
+ class Pow:
74
+ """Number power by a number"""
75
+
76
+ def __init__(self, number: Union[int, float], power_by: Union[int, float]) -> None:
77
+ self.number = number
78
+ self.power_by = power_by
79
+
80
+ def __str__(self) -> str:
81
+ if self.power_by == 1:
82
+ return str(self.number)
83
+ else:
84
+ return f"{self.number}^{self.power_by}"
85
+ # return f"{self.__class__.__name__}({self.number}, {self.power_by})"
86
+
87
+ def __repr__(self) -> str:
88
+ return self.__str__()
89
+
90
+ def to_list(self) -> List[Union[int, float]]:
91
+ """
92
+ Convert into list
93
+
94
+ :rtype: list[int | float]
95
+ """
96
+ return [self.number] * self.power_by
97
+
98
+ def calculate(self) -> float:
99
+ """
100
+ Calculate the ``self.number`` to the power of ``self.power_by``
101
+
102
+ :rtype: float
103
+ """
104
+ # return self.number**self.power_by
105
+ return math.pow(self.number, self.power_by)
106
+
107
+
108
+ class ListREPR(list):
109
+ """Show ``list`` in shorter form"""
110
+
111
+ def __repr__(self) -> str:
112
+ return _compress_list_for_print(self, 9)
113
+
114
+
115
+ class ListNoDunder(List[str]):
116
+ """Use with ``object.__dir__()``"""
117
+
118
+ def __repr__(self) -> str:
119
+ out = [x for x in self if not x.startswith("__")]
120
+ return out.__repr__()
121
+
122
+
123
+ class DictBoolTrue(Dict[Any, bool]):
124
+ """Only show items when ``values == True`` in ``__repr__()``"""
125
+
126
+ def __repr__(self) -> str:
127
+ temp = self.copy()
128
+ return _dict_bool(temp, True).__repr__()
129
+
130
+
131
+ class DictBoolFalse(Dict[Any, bool]):
132
+ """Only show items when ``values == False`` in ``__repr__()``"""
133
+
134
+ def __repr__(self) -> str:
135
+ temp = self.copy()
136
+ return _dict_bool(temp, False).__repr__()
137
+
138
+
139
+ # class DictNoDunder(dict): # W.I.P
140
+ # """Remove dunder methods in ``__repr__()`` of dict"""
141
+
142
+ # def __repr__(self) -> str:
143
+ # temp = self.copy()
144
+ # out = dict()
145
+ # for k, v in temp.items():
146
+ # if not str(k).startswith("__"):
147
+ # out.__setattr__(k, v)
148
+ # return out.__repr__()
149
+
150
+
40
151
  # Class
41
152
  ###########################################################################
42
153
  class Text(str):
43
154
  """
44
155
  ``str`` extension
45
156
  """
157
+
46
158
  def divide(self, string_split_size: int = 60) -> list:
47
159
  """
48
160
  Divide long string into smaller size
@@ -59,7 +171,7 @@ class Text(str):
59
171
  A list in which each item is a smaller
60
172
  string with the size of ``string_split_size``
61
173
  (need to be concaternate later)
62
-
174
+
63
175
 
64
176
  Example:
65
177
  --------
@@ -73,13 +185,13 @@ class Text(str):
73
185
  output.append(temp[:string_split_size])
74
186
  temp = temp[string_split_size:]
75
187
  return output
76
-
188
+
77
189
  def divide_with_variable(
78
- self,
79
- split_size: int = 60,
80
- split_var_len: int = 12,
81
- custom_var_name: Optional[str] = None,
82
- ) -> list:
190
+ self,
191
+ split_size: int = 60,
192
+ split_var_len: int = 12,
193
+ custom_var_name: Optional[str] = None,
194
+ ) -> list:
83
195
  """
84
196
  Divide long string into smaller size,
85
197
  then assign a random variable to splited
@@ -90,11 +202,11 @@ class Text(str):
90
202
  split_size : int
91
203
  Divide string every ``x`` character
92
204
  (Default: ``60``)
93
-
205
+
94
206
  split_var_len : int
95
207
  Length of variable name assigned to each item
96
208
  (Default: ``12``)
97
-
209
+
98
210
  custom_var_name : str
99
211
  Custom variable name when join string
100
212
 
@@ -129,30 +241,28 @@ class Text(str):
129
241
 
130
242
  temp = self.divide(split_size)
131
243
  output = []
132
-
244
+
133
245
  # split variable
134
246
  splt_var_len = split_var_len
135
247
  splt_len = len(temp)
136
248
 
137
249
  if custom_var_name is None:
138
250
  splt_name = Generator.generate_string(
139
- charset=Charset.ALPHABET,
140
- size=split_var_len,
141
- times=splt_len+1
251
+ charset=Charset.ALPHABET, size=split_var_len, times=splt_len + 1
142
252
  )
143
253
  for i in range(splt_len):
144
254
  output.append(f"{splt_name[i]}='{temp[i]}'")
145
255
  else:
146
256
  for i in range(splt_len):
147
257
  output.append(f"{custom_var_name}{i+1}='{temp[i]}'")
148
-
258
+
149
259
  # joined variable
150
260
  temp = []
151
261
  if custom_var_name is None:
152
262
  for i in range(splt_len):
153
263
  if i == 0:
154
264
  temp.append(f"{splt_name[-1]}=")
155
- if (i == splt_len-1):
265
+ if i == splt_len - 1:
156
266
  temp.append(f"{splt_name[i]}")
157
267
  else:
158
268
  temp.append(f"{splt_name[i]}+")
@@ -160,11 +270,11 @@ class Text(str):
160
270
  for i in range(splt_len):
161
271
  if i == 0:
162
272
  temp.append(f"{custom_var_name}=")
163
- if (i == splt_len-1):
273
+ if i == splt_len - 1:
164
274
  temp.append(f"{custom_var_name}{i+1}")
165
275
  else:
166
276
  temp.append(f"{custom_var_name}{i+1}+")
167
-
277
+
168
278
  output.append("".join(temp))
169
279
  if custom_var_name is None:
170
280
  output.append(splt_name[-1])
@@ -173,7 +283,6 @@ class Text(str):
173
283
 
174
284
  return output
175
285
 
176
-
177
286
  def analyze(self) -> dict:
178
287
  """
179
288
  String analyze (count number of type of character)
@@ -184,8 +293,8 @@ class Text(str):
184
293
  A dictionary contains number of digit character,
185
294
  uppercase character, lowercase character, and
186
295
  special character
187
-
188
-
296
+
297
+
189
298
  Example:
190
299
  --------
191
300
  >>> test = Text("Random T3xt!")
@@ -195,36 +304,30 @@ class Text(str):
195
304
 
196
305
  temp = self
197
306
 
198
- detail = {
199
- "digit": 0,
200
- "uppercase": 0,
201
- "lowercase": 0,
202
- "other": 0
203
- }
307
+ detail = {"digit": 0, "uppercase": 0, "lowercase": 0, "other": 0}
204
308
 
205
309
  for x in temp:
206
- if ord(x) in range(48, 58): #num
310
+ if ord(x) in range(48, 58): # num
207
311
  detail["digit"] += 1
208
- elif ord(x) in range(65, 91): #cap
312
+ elif ord(x) in range(65, 91): # cap
209
313
  detail["uppercase"] += 1
210
- elif ord(x) in range(97, 123): #low
314
+ elif ord(x) in range(97, 123): # low
211
315
  detail["lowercase"] += 1
212
316
  else:
213
317
  detail["other"] += 1
214
-
318
+
215
319
  return detail
216
-
217
320
 
218
- def reverse(self):
321
+ def reverse(self) -> "Text":
219
322
  """
220
323
  Reverse the string
221
-
324
+
222
325
  Returns
223
326
  -------
224
327
  Text
225
328
  Reversed string
226
-
227
-
329
+
330
+
228
331
  Example:
229
332
  --------
230
333
  >>> test = Text("Hello, World!")
@@ -233,7 +336,6 @@ class Text(str):
233
336
  """
234
337
  return __class__(self[::-1])
235
338
 
236
-
237
339
  def is_pangram(self) -> bool:
238
340
  """
239
341
  Check if string is a pangram
@@ -255,7 +357,7 @@ class Text(str):
255
357
  """
256
358
  Check if string is a palindrome
257
359
 
258
- A palindrome is a word, verse, or sentence
360
+ A palindrome is a word, verse, or sentence
259
361
  or a number that reads the same backward or forward
260
362
 
261
363
  Returns
@@ -267,7 +369,7 @@ class Text(str):
267
369
  text = self
268
370
  # Use string slicing [start:end:step]
269
371
  return text == text[::-1]
270
-
372
+
271
373
  def to_hex(self, raw: bool = False) -> str:
272
374
  r"""
273
375
  Convert string to hex form
@@ -291,10 +393,10 @@ class Text(str):
291
393
  '\\x48\\x65\\x6c\\x6c\\x6f\\x2c\\x20\\x57\\x6f\\x72\\x6c\\x64\\x21'
292
394
  """
293
395
  text = self
294
-
396
+
295
397
  byte_str = text.encode("utf-8")
296
398
  hex_str = byte_str.hex()
297
-
399
+
298
400
  if not raw:
299
401
  temp = []
300
402
  str_len = len(hex_str)
@@ -307,7 +409,7 @@ class Text(str):
307
409
  else:
308
410
  return hex_str
309
411
 
310
- def random_capslock(self, probability: int = 50):
412
+ def random_capslock(self, probability: int = 50) -> "Text":
311
413
  """
312
414
  Randomly capslock letter in string
313
415
 
@@ -316,7 +418,7 @@ class Text(str):
316
418
  probability : int
317
419
  Probability in range [0, 100]
318
420
  (Default: ``50``)
319
-
421
+
320
422
  Returns
321
423
  -------
322
424
  Text
@@ -331,7 +433,7 @@ class Text(str):
331
433
  """
332
434
  probability = set_min_max(probability)
333
435
  text = self.lower()
334
-
436
+
335
437
  temp = []
336
438
  for x in text:
337
439
  if random.randint(1, 100) <= probability:
@@ -340,22 +442,65 @@ class Text(str):
340
442
  logger.debug(temp)
341
443
  return __class__("".join(temp))
342
444
 
445
+ def reverse_capslock(self) -> "Text":
446
+ """
447
+ Reverse capslock in string
448
+
449
+ Returns
450
+ -------
451
+ Text
452
+ Reversed capslock ``Text``
453
+
454
+
455
+ Example:
456
+ --------
457
+ >>> test = Text("Foo")
458
+ >>> test.reverse_capslock()
459
+ 'fOO'
460
+ """
461
+ temp = list(self)
462
+ for i, x in enumerate(temp):
463
+ if x.isupper():
464
+ temp[i] = x.lower()
465
+ else:
466
+ temp[i] = x.upper()
467
+ return __class__("".join(temp))
468
+
469
+ def to_list(self) -> List[str]:
470
+ """
471
+ Convert into list
472
+
473
+ Returns
474
+ -------
475
+ list[str]
476
+ List of string
477
+
478
+
479
+ Example:
480
+ --------
481
+ >>> test = Text("test")
482
+ >>> test.to_list()
483
+ ['t', 'e', 's', 't']
484
+ """
485
+ return list(self)
486
+
343
487
 
344
488
  class IntNumber(int):
345
489
  """
346
490
  ``int`` extension
347
491
  """
492
+
348
493
  # convert stuff
349
494
  def to_binary(self) -> str:
350
495
  """
351
496
  Convert to binary number
352
-
497
+
353
498
  Returns
354
499
  -------
355
500
  str
356
501
  Binary number
357
-
358
-
502
+
503
+
359
504
  Example:
360
505
  --------
361
506
  >>> test = IntNumber(10)
@@ -363,7 +508,7 @@ class IntNumber(int):
363
508
  '1010'
364
509
  """
365
510
  return format(self, "b")
366
-
511
+
367
512
  def to_celcius_degree(self) -> float:
368
513
  """
369
514
  Convert into Celcius degree as if ``self`` is Fahrenheit degree
@@ -382,7 +527,7 @@ class IntNumber(int):
382
527
  """
383
528
  c_degree = (self - 32) / 1.8
384
529
  return c_degree
385
-
530
+
386
531
  def to_fahrenheit_degree(self) -> float:
387
532
  """
388
533
  Convert into Fahrenheit degree as if ``self`` is Celcius degree
@@ -402,8 +547,19 @@ class IntNumber(int):
402
547
  f_degree = (self * 1.8) + 32
403
548
  return f_degree
404
549
 
405
-
406
550
  # is_stuff
551
+ def is_even(self) -> bool:
552
+ """
553
+ An even number is a number which divisible by 2
554
+
555
+ Returns
556
+ -------
557
+ bool
558
+ | ``True`` if an even number
559
+ | ``False`` if not an even number
560
+ """
561
+ return self % 2 == 0
562
+
407
563
  def is_prime(self) -> bool:
408
564
  """
409
565
  Check if the integer is a prime number or not
@@ -420,14 +576,14 @@ class IntNumber(int):
420
576
  | ``False`` if not a prime number
421
577
  """
422
578
  number = self
423
-
424
- if int(number) <= 1:
579
+
580
+ if number <= 1:
425
581
  return False
426
- for i in range(2, int(math.sqrt(number)) + 1):# divisor range
427
- if (number % i == 0):
582
+ for i in range(2, int(math.sqrt(number)) + 1): # divisor range
583
+ if number % i == 0:
428
584
  return False
429
585
  return True
430
-
586
+
431
587
  def is_twisted_prime(self) -> bool:
432
588
  """
433
589
  A number is said to be twisted prime if
@@ -445,7 +601,7 @@ class IntNumber(int):
445
601
  rev = self.reverse().is_prime()
446
602
  logger.debug(f"is prime when reversed: {rev}")
447
603
  return prime and rev
448
-
604
+
449
605
  def is_perfect(self) -> bool:
450
606
  """
451
607
  Check if integer is perfect number
@@ -494,15 +650,15 @@ class IntNumber(int):
494
650
  33_550_336,
495
651
  8_589_869_056,
496
652
  137_438_691_328,
497
- 2_305_843_008_139_952_128
653
+ 2_305_843_008_139_952_128,
498
654
  ]
499
-
655
+
500
656
  if int(number) in perfect_number:
501
657
  return True
502
-
658
+
503
659
  elif int(number) < perfect_number[-1]:
504
660
  return False
505
-
661
+
506
662
  else:
507
663
  # Faster way to check
508
664
  perfect_number_index = [
@@ -551,13 +707,13 @@ class IntNumber(int):
551
707
  ## 82_589_933
552
708
  ]
553
709
  for x in perfect_number_index:
554
- # a perfect number have a form of (2**(n-1))*((2**n)-1)
555
- perfect_number = ((2**(x-1))*((2**x)-1))
710
+ # a perfect number have a form of (2**(n-1))*((2**n)-1)
711
+ perfect_number = (2 ** (x - 1)) * ((2**x) - 1)
556
712
  if number < perfect_number:
557
713
  return False
558
714
  elif number == perfect_number:
559
715
  return True
560
-
716
+
561
717
  # Manual way when above method not working
562
718
  # sum
563
719
  s = 1
@@ -565,10 +721,10 @@ class IntNumber(int):
565
721
  i = 2
566
722
  while i * i <= number:
567
723
  if number % i == 0:
568
- s += + i + number/i
724
+ s += +i + number / i
569
725
  i += 1
570
726
  # s == number -> perfect
571
- return (True if s == number and number!=1 else False)
727
+ return True if s == number and number != 1 else False
572
728
 
573
729
  def is_narcissistic(self) -> bool:
574
730
  """
@@ -580,34 +736,40 @@ class IntNumber(int):
580
736
  or a plus perfect number) in a given number base ``b``
581
737
  is a number that is the sum of its own digits
582
738
  each raised to the power of the number of digits.
583
-
739
+
584
740
  Returns
585
741
  -------
586
742
  bool
587
743
  | ``True`` if a narcissistic number
588
744
  | ``False`` if not a narcissistic number
589
745
  """
590
- check = sum([int(x) ** len(str(self)) for x in str(self)])
591
- return self == check
746
+ try:
747
+ check = sum([int(x) ** len(str(self)) for x in str(self)])
748
+ return self == check
749
+ except:
750
+ return False
592
751
 
593
- def reverse(self):
752
+ def reverse(self) -> "IntNumber":
594
753
  """
595
- Reverse a number
596
-
754
+ Reverse a number. Reverse ``abs(number)`` if ``number < 0``
755
+
597
756
  Returns
598
757
  -------
599
758
  IntNumber
600
759
  Reversed number
601
-
602
-
760
+
761
+
603
762
  Example:
604
763
  --------
605
764
  >>> test = IntNumber(102)
606
765
  >>> test.reverse()
607
766
  201
608
767
  """
609
- return __class__(str(self)[::-1])
610
-
768
+ number = self
769
+ if number <= 1:
770
+ number *= -1
771
+ return __class__(str(number)[::-1])
772
+
611
773
  def is_palindromic(self) -> bool:
612
774
  """
613
775
  A palindromic number (also known as a numeral palindrome
@@ -621,7 +783,7 @@ class IntNumber(int):
621
783
  | ``False`` if not a palindromic number
622
784
  """
623
785
  return self == self.reverse()
624
-
786
+
625
787
  def is_palindromic_prime(self) -> bool:
626
788
  """
627
789
  A palindormic prime is a number which is both palindromic and prime
@@ -633,10 +795,9 @@ class IntNumber(int):
633
795
  | ``False`` if not a palindormic prime number
634
796
  """
635
797
  return self.is_palindromic() and self.is_prime()
636
-
637
798
 
638
799
  # calculation stuff
639
- def lcm(self, with_number: int):
800
+ def lcm(self, with_number: int) -> "IntNumber":
640
801
  """
641
802
  Least common multiple of ``self`` and ``with_number``
642
803
 
@@ -658,15 +819,41 @@ class IntNumber(int):
658
819
  510
659
820
  """
660
821
  return __class__((self * with_number) // math.gcd(self, with_number))
661
-
662
- def add_to_one_digit(self, master_number: bool = False):
822
+
823
+ def gcd(self, with_number: int) -> "IntNumber":
824
+ """
825
+ Greatest common divisor of ``self`` and ``with_number``
826
+
827
+ Parameters
828
+ ----------
829
+ with_number : int
830
+ The number that want to find GCD with
831
+
832
+ Returns
833
+ -------
834
+ IntNumber
835
+ Greatest common divisor
836
+
837
+
838
+ Example:
839
+ --------
840
+ >>> test = IntNumber(1024)
841
+ >>> test.gcd(8)
842
+ 8
843
+ """
844
+ if python_version.micro < 9:
845
+ return __class__(math.gcd(self, with_number))
846
+ else:
847
+ return __class__(math.lcm(self, with_number))
848
+
849
+ def add_to_one_digit(self, master_number: bool = False) -> "IntNumber":
663
850
  """
664
- Convert ``self`` into 1-digit number
851
+ Convert ``self`` into 1-digit number
665
852
  by adding all of the digits together
666
853
 
667
854
  Parameters
668
855
  ----------
669
- master_number: bool
856
+ master_number : bool
670
857
  | Break when sum = ``22`` or ``11`` (numerology)
671
858
  | (Default: ``False``)
672
859
 
@@ -687,42 +874,222 @@ class IntNumber(int):
687
874
  11
688
875
  """
689
876
  number = self
877
+ if number < 0:
878
+ number *= -1
690
879
  logger.debug(f"Current number: {number}")
691
880
  while len(str(number)) != 1:
692
881
  number = sum(map(int, str(number)))
693
882
  if master_number:
694
883
  if number == 22 or number == 11:
695
- break # Master number
884
+ break # Master number
696
885
  logger.debug(f"Sum after loop: {number}")
697
886
  return __class__(number)
698
887
 
888
+ def divisible_list(self, short_form: bool = True) -> List[int]:
889
+ """
890
+ A list of divisible number
891
+
892
+ Parameters
893
+ ----------
894
+ short_form : bool
895
+ | Show divisible list in short form
896
+ | Normal example: ``[1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]``
897
+ | Short form example: ``[1, 2, 4, 8, ...,128, 256, 512, 1024] [Len: 11]``
898
+ | (Default: ``True``)
899
+
900
+ Returns
901
+ -------
902
+ list[int]
903
+ A list of divisible number
904
+
905
+
906
+ Example:
907
+ --------
908
+ >>> test = IntNumber(1024)
909
+ >>> test.divisible_list(short_form=False)
910
+ [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]
911
+ """
912
+
913
+ if self <= 1:
914
+ return [1]
915
+ divi_list = [x for x in range(1, int(self / 2) + 1) if self % x == 0] + [self]
916
+
917
+ if short_form:
918
+ return divi_list
919
+ # return ListREPR(divi_list) ## FIX LATER
920
+ return divi_list
921
+
922
+ def prime_factor(self, short_form: bool = True) -> Union[List[int], List[Pow]]:
923
+ """
924
+ Prime factor
699
925
 
700
- class ListKai(list):
926
+ Parameters
927
+ ----------
928
+ short_form : bool
929
+ | Show prime list in short form
930
+ | Normal example: ``[2, 2, 2, 3, 3]``
931
+ | Short form example: ``[2^3, 3^2]``
932
+ | (Default: ``True``)
933
+
934
+ Returns
935
+ -------
936
+ list[int] | list[Pow]
937
+ | List of prime number that when multiplied together == ``self``
938
+ | list[int]: Long form
939
+ | list[Pow]: Short form
940
+
941
+
942
+ Example:
943
+ --------
944
+ >>> test = IntNumber(1024)
945
+ >>> test.prime_factor()
946
+ [2^10]
947
+
948
+ >>> test = IntNumber(1024)
949
+ >>> test.prime_factor(short_form=False)
950
+ [2, 2, 2, 2, 2, 2, 2, 2, 2, 2]
951
+ """
952
+ # Generate list
953
+ factors = []
954
+ divisor = 2
955
+ number = int(self)
956
+ if number <= 1:
957
+ return [number]
958
+ while divisor <= number:
959
+ if number % divisor == 0:
960
+ factors.append(divisor)
961
+ number //= divisor # number = number // divisor
962
+ else:
963
+ divisor += 1
964
+
965
+ # Output
966
+ if short_form:
967
+ temp = dict(Counter(factors))
968
+ return [Pow(k, v) for k, v in temp.items()]
969
+ return factors
970
+
971
+ # analyze
972
+ def analyze(self, short_form: bool = True) -> Dict[str, Dict[str, Any]]:
973
+ """
974
+ Analyze the number with almost all ``IntNumber`` method
975
+
976
+ Parameters
977
+ ----------
978
+ short_form : bool
979
+ | Enable short form for some items
980
+ | (Default: ``True``)
981
+
982
+ Returns
983
+ -------
984
+ dict[str, dict[str, Any]]
985
+ Detailed analysis
986
+
987
+
988
+ Example:
989
+ --------
990
+ >>> test = IntNumber(1024)
991
+ >>> test.analyze()
992
+ {
993
+ 'summary': {'number': 1024, 'length': 4, 'even': True, 'prime factor': [2^10], 'divisible': [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]},
994
+ 'convert': {'binary': '10000000000', 'octa': '2000', 'hex': '400', 'reverse': 4201, 'add to one': 7},
995
+ 'characteristic': {'prime': False, 'twisted prime': False, 'perfect': False, 'narcissistic': False, 'palindromic': False, 'palindromic prime': False}
996
+ }
997
+ """
998
+ output = {
999
+ "summary": {
1000
+ "number": self,
1001
+ "length": len(str(self)),
1002
+ "even": self.is_even(),
1003
+ "prime factor": self.prime_factor(short_form=short_form),
1004
+ "divisible": self.divisible_list(short_form=short_form),
1005
+ },
1006
+ "convert": {
1007
+ "binary": bin(self)[2:],
1008
+ "octa": oct(self)[2:],
1009
+ "hex": hex(self)[2:],
1010
+ # "hash": hash(self),
1011
+ "reverse": self.reverse(),
1012
+ "add to one": self.add_to_one_digit(),
1013
+ },
1014
+ }
1015
+ characteristic = {
1016
+ "prime": self.is_prime(),
1017
+ "twisted prime": self.is_twisted_prime(),
1018
+ "perfect": self.is_perfect(),
1019
+ "narcissistic": self.is_narcissistic(),
1020
+ "palindromic": self.is_palindromic(),
1021
+ "palindromic prime": self.is_palindromic_prime(),
1022
+ }
1023
+ if short_form:
1024
+ characteristic = DictBoolTrue(characteristic)
1025
+
1026
+ output["characteristic"] = characteristic
1027
+ return output
1028
+
1029
+
1030
+ class ListExt(list):
701
1031
  """
702
1032
  ``list`` extension
703
1033
  """
704
- def stringify(self):
1034
+
1035
+ def stringify(self) -> "ListExt":
705
1036
  """
706
1037
  Convert all item in ``list`` into string
707
1038
 
708
1039
  Returns
709
1040
  -------
710
- ListKai
711
- A list with all items with type: string
1041
+ ListExt
1042
+ A list with all items with type <str`>
712
1043
 
713
1044
 
714
1045
  Example:
715
1046
  --------
716
- >>> test = ListKai([1, 1, 1, 2, 2, 3])
1047
+ >>> test = ListExt([1, 1, 1, 2, 2, 3])
717
1048
  >>> test.stringify()
718
1049
  ['1', '1', '1', '2', '2', '3']
719
1050
  """
720
- return ListKai(map(str, self))
1051
+ return ListExt(map(str, self))
1052
+
1053
+ def head(self, number_of_items: int = 5) -> list:
1054
+ """
1055
+ Show first ``number_of_items`` items in ``ListExt``
1056
+
1057
+ Parameters
1058
+ ----------
1059
+ number_of_items : int
1060
+ | Number of items to shows at once
1061
+ | (Default: ``5``)
721
1062
 
722
- def sorts(self, reverse: bool = False):
1063
+ Returns
1064
+ -------
1065
+ list
1066
+ Filtered list
1067
+ """
1068
+ number_of_items = set_min_max(number_of_items, min_value=0, max_value=len(self))
1069
+ return self[:number_of_items]
1070
+
1071
+ def tail(self, number_of_items: int = 5) -> list:
1072
+ """
1073
+ Show last ``number_of_items`` items in ``ListExt``
1074
+
1075
+ Parameters
1076
+ ----------
1077
+ number_of_items : int
1078
+ | Number of items to shows at once
1079
+ | (Default: ``5``)
1080
+
1081
+ Returns
1082
+ -------
1083
+ list
1084
+ Filtered list
1085
+ """
1086
+ number_of_items = set_min_max(number_of_items, min_value=0, max_value=len(self))
1087
+ return self[::-1][:number_of_items][::-1]
1088
+
1089
+ def sorts(self, reverse: bool = False) -> "ListExt":
723
1090
  """
724
1091
  Sort all items (with different type) in ``list``
725
-
1092
+
726
1093
  Parameters
727
1094
  ----------
728
1095
  reverse : bool
@@ -732,13 +1099,13 @@ class ListKai(list):
732
1099
 
733
1100
  Returns
734
1101
  -------
735
- ListKai
1102
+ ListExt
736
1103
  A sorted list
737
1104
 
738
1105
 
739
1106
  Example:
740
1107
  --------
741
- >>> test = ListKai([9, "abc", 3.5, "aaa", 1, 1.4])
1108
+ >>> test = ListExt([9, "abc", 3.5, "aaa", 1, 1.4])
742
1109
  >>> test.sorts()
743
1110
  [1, 9, 'aaa', 'abc', 1.4, 3.5]
744
1111
  """
@@ -750,20 +1117,18 @@ class ListKai(list):
750
1117
  logger.debug(f"Type weight: {type_weights}")
751
1118
 
752
1119
  output = sorted(
753
- lst,
754
- key=lambda x: (type_weights[type(x)], str(x)),
755
- reverse=reverse
1120
+ lst, key=lambda x: (type_weights[type(x)], str(x)), reverse=reverse
756
1121
  )
757
1122
 
758
1123
  logger.debug(output)
759
1124
  return __class__(output)
760
-
1125
+
761
1126
  def freq(
762
- self,
763
- sort: bool = False,
764
- num_of_first_char: Optional[int] = None,
765
- appear_increment: bool = False
766
- ):
1127
+ self,
1128
+ sort: bool = False,
1129
+ num_of_first_char: Optional[int] = None,
1130
+ appear_increment: bool = False,
1131
+ ):
767
1132
  """
768
1133
  Find frequency of each item in list
769
1134
 
@@ -772,12 +1137,12 @@ class ListKai(list):
772
1137
  sort : bool
773
1138
  | if ``True``: Sorts the output in ascending order
774
1139
  | if ``False``: No sort
775
-
1140
+
776
1141
  num_of_first_char : int | None
777
1142
  | Number of first character taken into account to sort
778
1143
  | (Default: None)
779
1144
  | (num_of_first_char = ``1``: first character in each item)
780
-
1145
+
781
1146
  appear_increment : bool
782
1147
  | return incremental index list of each item when sort
783
1148
  | (Default: ``False``)
@@ -786,18 +1151,18 @@ class ListKai(list):
786
1151
  -------
787
1152
  dict
788
1153
  A dict that show frequency
789
-
1154
+
790
1155
  list
791
1156
  Incremental index list
792
-
1157
+
793
1158
 
794
1159
  Example:
795
1160
  --------
796
- >>> test = ListKai([1, 1, 2, 3, 5, 5])
1161
+ >>> test = ListExt([1, 1, 2, 3, 5, 5])
797
1162
  >>> test.freq()
798
1163
  {1: 2, 2: 1, 3: 1, 5: 2}
799
1164
 
800
- >>> test = ListKai([1, 1, 2, 3, 3, 4, 5, 6])
1165
+ >>> test = ListExt([1, 1, 2, 3, 3, 4, 5, 6])
801
1166
  >>> test.freq(appear_increment=True)
802
1167
  [2, 3, 5, 6, 7, 8]
803
1168
  """
@@ -806,7 +1171,7 @@ class ListKai(list):
806
1171
  data = self.sorts()
807
1172
  else:
808
1173
  data = self.copy()
809
-
1174
+
810
1175
  if num_of_first_char is None:
811
1176
  temp = Counter(data)
812
1177
  else:
@@ -818,21 +1183,23 @@ class ListKai(list):
818
1183
  else:
819
1184
  logger.debug(f"Freq of first {num_of_first_char} char")
820
1185
  temp = Counter([str(x)[:num_of_first_char] for x in data])
821
-
1186
+
822
1187
  try:
823
1188
  times_appear = dict(sorted(temp.items()))
824
1189
  except:
825
1190
  times_appear = dict(__class__(temp.items()).sorts())
826
1191
  logger.debug(times_appear)
827
-
1192
+
828
1193
  if appear_increment:
829
- times_appear_increment = list(accumulate(times_appear.values(), operator.add))
1194
+ times_appear_increment = list(
1195
+ accumulate(times_appear.values(), operator.add)
1196
+ )
830
1197
  logger.debug(times_appear_increment)
831
1198
  return times_appear_increment
832
1199
  else:
833
1200
  return times_appear
834
1201
 
835
- def slice_points(self, points: list):
1202
+ def slice_points(self, points: list) -> List[list]:
836
1203
  """
837
1204
  Slices a list at specific indices into constituent lists.
838
1205
 
@@ -840,7 +1207,7 @@ class ListKai(list):
840
1207
  ----------
841
1208
  points : list
842
1209
  List of indices to slice
843
-
1210
+
844
1211
  Returns
845
1212
  -------
846
1213
  list[list]
@@ -849,28 +1216,28 @@ class ListKai(list):
849
1216
 
850
1217
  Example:
851
1218
  --------
852
- >>> test = ListKai([1, 1, 2, 3, 3, 4, 5, 6])
1219
+ >>> test = ListExt([1, 1, 2, 3, 3, 4, 5, 6])
853
1220
  >>> test.slice_points([2, 5])
854
1221
  [[1, 1], [2, 3, 3], [4, 5, 6]]
855
1222
  """
856
1223
  points.append(len(self))
857
1224
  data = self.copy()
858
1225
  # return [data[points[i]:points[i+1]] for i in range(len(points)-1)]
859
- return [data[i1:i2] for i1, i2 in zip([0]+points[:-1], points)]
1226
+ return [data[i1:i2] for i1, i2 in zip([0] + points[:-1], points)]
860
1227
 
861
- def pick_one(self):
1228
+ def pick_one(self) -> Any:
862
1229
  """
863
1230
  Pick one random items from ``list``
864
-
1231
+
865
1232
  Returns
866
1233
  -------
867
- Any | None
1234
+ Any
868
1235
  Random value
869
1236
 
870
1237
 
871
1238
  Example:
872
1239
  --------
873
- >>> test = ListKai(["foo", "bar"])
1240
+ >>> test = ListExt(["foo", "bar"])
874
1241
  >>> test.pick_one()
875
1242
  'bar'
876
1243
  """
@@ -880,33 +1247,50 @@ class ListKai(list):
880
1247
  return out
881
1248
  else:
882
1249
  logger.debug("List empty!")
883
- return None
884
-
885
- def len_items(self):
1250
+ raise IndexError("List empty!")
1251
+
1252
+ def get_random(self, number_of_items: int = 5) -> list:
1253
+ """
1254
+ Get ``number_of_items`` random items in ``ListExt``
1255
+
1256
+ Parameters
1257
+ ----------
1258
+ number_of_items : int
1259
+ | Number random of items
1260
+ | (Default: ``5``)
1261
+
1262
+ Returns
1263
+ -------
1264
+ list
1265
+ Filtered list
1266
+ """
1267
+ return [self.pick_one() for _ in range(number_of_items)]
1268
+
1269
+ def len_items(self) -> "ListExt":
886
1270
  """
887
1271
  ``len()`` for every item in ``list[str]``
888
1272
 
889
1273
  Returns
890
1274
  -------
891
- ListKai
1275
+ ListExt
892
1276
  List of ``len()``'ed value
893
1277
 
894
1278
 
895
1279
  Example:
896
1280
  --------
897
- >>> test = ListKai(["foo", "bar", "pizza"])
1281
+ >>> test = ListExt(["foo", "bar", "pizza"])
898
1282
  >>> test.len_items()
899
1283
  [3, 3, 5]
900
1284
  """
901
- out = ListKai([len(str(x)) for x in self])
902
- # out = ListKai(map(lambda x: len(str(x)), self))
1285
+ out = ListExt([len(str(x)) for x in self])
1286
+ # out = ListExt(map(lambda x: len(str(x)), self))
903
1287
  logger.debug(out)
904
1288
  return out
905
1289
 
906
1290
  def mean_len(self) -> float:
907
1291
  """
908
1292
  Average length of every item
909
-
1293
+
910
1294
  Returns
911
1295
  -------
912
1296
  float
@@ -915,69 +1299,69 @@ class ListKai(list):
915
1299
 
916
1300
  Example:
917
1301
  --------
918
- >>> test = ListKai(["foo", "bar", "pizza"])
1302
+ >>> test = ListExt(["foo", "bar", "pizza"])
919
1303
  >>> test.mean_len()
920
1304
  3.6666666666666665
921
1305
  """
922
- out = sum(self.len_items())/len(self)
1306
+ out = sum(self.len_items()) / len(self)
923
1307
  logger.debug(out)
924
1308
  return out
925
-
926
- def apply(self, func):
1309
+
1310
+ def apply(self, func: Callable) -> "ListExt":
927
1311
  """
928
1312
  Apply function to each entry
929
-
1313
+
930
1314
  Parameters
931
1315
  ----------
932
1316
  func : Callable
933
1317
  Callable function
934
-
1318
+
935
1319
  Returns
936
1320
  -------
937
- ListKai
938
- ListKai
1321
+ ListExt
1322
+ ListExt
939
1323
 
940
1324
 
941
1325
  Example:
942
1326
  --------
943
- >>> test = ListKai([1, 2, 3])
1327
+ >>> test = ListExt([1, 2, 3])
944
1328
  >>> test.apply(str)
945
1329
  ['1', '2', '3']
946
1330
  """
947
1331
  # return __class__(func(x) for x in self)
948
1332
  return __class__(map(func, self))
949
1333
 
950
- def unique(self):
1334
+ def unique(self) -> "ListExt":
951
1335
  """
952
1336
  Remove duplicates
953
1337
 
954
1338
  Returns
955
1339
  -------
956
- ListKai
1340
+ ListExt
957
1341
  Duplicates removed list
958
-
959
-
1342
+
1343
+
960
1344
  Example:
961
1345
  --------
962
- >>> test = ListKai([1, 1, 1, 2, 2, 3])
1346
+ >>> test = ListExt([1, 1, 1, 2, 2, 3])
963
1347
  >>> test.unique()
964
1348
  [1, 2, 3]
965
1349
  """
966
1350
  return __class__(set(self))
967
-
968
- def group_by_unique(self):
1351
+
1352
+ def group_by_unique(self) -> "ListExt":
969
1353
  """
970
1354
  Group duplicated elements into list
971
1355
 
972
1356
  Returns
973
1357
  -------
974
- ListKai
1358
+ ListExt
975
1359
  Grouped value
976
-
1360
+
977
1361
 
978
1362
  Example:
979
1363
  --------
980
- >>> test = ListKai([1, 2, 3, 1, 3, 3, 2])
1364
+ >>> test = ListExt([1, 2, 3, 1, 3, 3, 2])
981
1365
  >>> test.group_by_unique()
982
1366
  [[1, 1], [2, 2], [3, 3, 3]]
983
1367
  """
@@ -989,33 +1373,40 @@ class ListKai(list):
989
1373
  temp = groupby(self.sorts())
990
1374
  return __class__([list(g) for _, g in temp])
991
1375
 
1376
+ @staticmethod
1377
+ def _group_by_unique(iterable: list) -> List[list]:
1378
+ """
1379
+ Static method for ``group_by_unique``
1380
+ """
1381
+ return list([list(g) for _, g in groupby(iterable)])
1382
+
992
1383
  def group_by_pair_value(self, max_loop: int = 3) -> List[list]:
993
1384
  """
994
- Assume each ``list`` in ``list`` is a pair value,
1385
+ Assume each ``list`` in ``list`` is a pair value,
995
1386
  returns a ``list`` contain all paired value
996
1387
 
997
1388
  Parameters
998
1389
  ----------
999
1390
  max_loop : int
1000
1391
  Times to run functions (minimum: ``3``)
1001
-
1392
+
1002
1393
  Returns
1003
1394
  -------
1004
1395
  list[list]
1005
1396
  Grouped value
1006
-
1397
+
1007
1398
 
1008
1399
  Example:
1009
1400
  --------
1010
- >>> test = ListKai([[1, 2], [2, 3], [4, 3], [5, 6]])
1401
+ >>> test = ListExt([[1, 2], [2, 3], [4, 3], [5, 6]])
1011
1402
  >>> test.group_by_pair_value()
1012
1403
  [[1, 2, 3, 4], [5, 6]]
1013
1404
 
1014
- >>> test = ListKai([[8, 3], [4, 6], [6, 3], [5, 2], [7, 2]])
1405
+ >>> test = ListExt([[8, 3], [4, 6], [6, 3], [5, 2], [7, 2]])
1015
1406
  >>> test.group_by_pair_value()
1016
1407
  [[8, 3, 4, 6], [2, 5, 7]]
1017
1408
 
1018
- >>> test = ListKai([["a", 4], ["b", 4], [5, "c"]])
1409
+ >>> test = ListExt([["a", 4], ["b", 4], [5, "c"]])
1019
1410
  >>> test.group_by_pair_value()
1020
1411
  [['a', 4, 'b'], ['c', 5]]
1021
1412
  """
@@ -1024,7 +1415,6 @@ class ListKai(list):
1024
1415
 
1025
1416
  # Init loop
1026
1417
  for _ in range(set_min(max_loop, min_value=3)):
1027
-
1028
1418
  temp: Dict[Any, list] = {}
1029
1419
  # Make dict{key: all `item` that contains `key`}
1030
1420
  for item in iter:
@@ -1037,19 +1427,76 @@ class ListKai(list):
1037
1427
  # Flatten dict.values
1038
1428
  for k, v in temp.items():
1039
1429
  temp[k] = list(set(chain(*v)))
1040
-
1430
+
1041
1431
  iter = list(temp.values())
1042
1432
 
1043
1433
  return list(x for x, _ in groupby(iter))
1044
1434
 
1435
+ def flatten(self) -> "ListExt":
1436
+ """
1437
+ Flatten the list
1438
+
1439
+ Returns
1440
+ -------
1441
+ ListExt
1442
+ Flattened list
1443
+
1045
1444
 
1046
- class DictKai(dict):
1445
+ Example:
1446
+ --------
1447
+ >>> test = ListExt([["test"], ["test", "test"], ["test"]])
1448
+ >>> test.flatten()
1449
+ ['test', 'test', 'test', 'test']
1450
+ """
1451
+ try:
1452
+ return ListExt(chain(*self))
1453
+ except:
1454
+ temp = list(map(lambda x: x if isinstance(x, list) else [x], self))
1455
+ return ListExt(chain(*temp))
1456
+
1457
+ def numbering(self, start: int = 0) -> "ListExt":
1458
+ """
1459
+ Number the item in list
1460
+ (``enumerate`` wrapper)
1461
+
1462
+ Parameters
1463
+ ----------
1464
+ start : int
1465
+ Start from which number
1466
+ (Default: ``0``)
1467
+
1468
+ Returns
1469
+ -------
1470
+ ListExt
1471
+ Counted list
1472
+
1473
+
1474
+ Example:
1475
+ --------
1476
+ >>> test = ListExt([9, 9, 9])
1477
+ >>> test.numbering()
1478
+ [(0, 9), (1, 9), (2, 9)]
1479
+ """
1480
+ start = set_min(start, min_value=0)
1481
+ return ListExt(enumerate(self, start=start))
1482
+
1483
+ @staticmethod
1484
+ def _numbering(iterable: list, start: int = 0) -> List[Tuple[int, Any]]:
1485
+ """
1486
+ Static method for ``numbering``
1487
+ """
1488
+ start = set_min(start, min_value=0)
1489
+ return list(enumerate(iterable, start=start))
1490
+
1491
+
1492
+ class DictExt(dict):
1047
1493
  """
1048
1494
  ``dict`` extension
1049
1495
  """
1496
+
1050
1497
  def analyze(self) -> dict:
1051
1498
  """
1052
- Analyze all the key values (``int``, ``float``)
1499
+ Analyze all the key values (``int``, ``float``)
1053
1500
  in ``dict`` then return highest/lowest index
1054
1501
 
1055
1502
  Returns
@@ -1060,7 +1507,7 @@ class DictKai(dict):
1060
1507
 
1061
1508
  Example:
1062
1509
  --------
1063
- >>> test = DictKai({
1510
+ >>> test = DictExt({
1064
1511
  >>> "abc": 9,
1065
1512
  >>> "def": 9,
1066
1513
  >>> "ghi": 8,
@@ -1093,38 +1540,71 @@ class DictKai(dict):
1093
1540
  "max_value": max_val,
1094
1541
  "min_value": min_val,
1095
1542
  "max": max_list,
1096
- "min": min_list
1543
+ "min": min_list,
1097
1544
  }
1098
1545
 
1099
1546
  logger.debug(output)
1100
1547
  return output
1101
-
1548
+
1102
1549
  except:
1103
1550
  err_msg = "Value must be int or float"
1104
1551
  logger.error(err_msg)
1105
1552
  raise ValueError(err_msg)
1106
-
1107
- def swap_items(self):
1553
+
1554
+ def swap_items(self) -> "DictExt":
1108
1555
  """
1109
1556
  Swap ``dict.keys()`` with ``dict.values()``
1110
1557
 
1111
1558
  Returns
1112
1559
  -------
1113
- DictKai
1560
+ DictExt
1114
1561
  Swapped dict
1115
1562
 
1116
1563
 
1117
1564
  Example:
1118
1565
  --------
1119
- >>> test = DictKai({"abc": 9})
1566
+ >>> test = DictExt({"abc": 9})
1120
1567
  >>> test.swap_items()
1121
1568
  {9: 'abc'}
1122
1569
  """
1123
1570
  return __class__(zip(self.values(), self.keys()))
1124
1571
 
1572
+ def apply(self, func: Callable, apply_to_value: bool = True) -> "DictExt":
1573
+ """
1574
+ Apply function to ``DictExt.keys()`` or ``DictExt.values()``
1575
+
1576
+ Parameters
1577
+ ----------
1578
+ func : Callable
1579
+ Callable function
1580
+
1581
+ apply_to_value : bool
1582
+ | ``True``: Apply ``func`` to ``DictExt.values()``
1583
+ | ``False``: Apply ``func`` to ``DictExt.keys()``
1584
+
1585
+ Returns
1586
+ -------
1587
+ DictExt
1588
+ DictExt
1589
+
1590
+
1591
+ Example:
1592
+ --------
1593
+ >>> test = DictExt({"abc": 9})
1594
+ >>> test.apply(str)
1595
+ {'abc': '9'}
1596
+ """
1597
+ if apply_to_value:
1598
+ k = self.keys()
1599
+ v = map(func, self.values())
1600
+ else:
1601
+ k = map(func, self.keys())
1602
+ v = self.values()
1603
+ return __class__(zip(k, v))
1125
1604
 
1126
1605
 
1127
1606
  # Run
1128
1607
  ###########################################################################
1129
1608
  if __name__ == "__main__":
1130
1609
  logger.setLevel(10)
1610
+ # from rich import print