absfuyu 4.2.0__py3-none-any.whl → 5.0.1__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 (72) hide show
  1. absfuyu/__init__.py +4 -4
  2. absfuyu/__main__.py +13 -1
  3. absfuyu/cli/__init__.py +2 -2
  4. absfuyu/cli/color.py +9 -2
  5. absfuyu/cli/config_group.py +2 -2
  6. absfuyu/cli/do_group.py +2 -37
  7. absfuyu/cli/game_group.py +2 -2
  8. absfuyu/cli/tool_group.py +7 -7
  9. absfuyu/config/__init__.py +17 -34
  10. absfuyu/core/__init__.py +49 -0
  11. absfuyu/core/baseclass.py +299 -0
  12. absfuyu/core/baseclass2.py +165 -0
  13. absfuyu/core/decorator.py +67 -0
  14. absfuyu/core/docstring.py +166 -0
  15. absfuyu/core/dummy_cli.py +67 -0
  16. absfuyu/core/dummy_func.py +49 -0
  17. absfuyu/dxt/__init__.py +42 -0
  18. absfuyu/dxt/dictext.py +201 -0
  19. absfuyu/dxt/dxt_support.py +79 -0
  20. absfuyu/dxt/intext.py +586 -0
  21. absfuyu/dxt/listext.py +508 -0
  22. absfuyu/dxt/strext.py +530 -0
  23. absfuyu/extra/__init__.py +12 -0
  24. absfuyu/extra/beautiful.py +252 -0
  25. absfuyu/{extensions → extra}/data_analysis.py +51 -82
  26. absfuyu/fun/__init__.py +110 -135
  27. absfuyu/fun/tarot.py +11 -19
  28. absfuyu/game/__init__.py +8 -2
  29. absfuyu/game/game_stat.py +8 -2
  30. absfuyu/game/sudoku.py +9 -3
  31. absfuyu/game/tictactoe.py +14 -7
  32. absfuyu/game/wordle.py +16 -10
  33. absfuyu/general/__init__.py +8 -81
  34. absfuyu/general/content.py +24 -38
  35. absfuyu/general/human.py +108 -228
  36. absfuyu/general/shape.py +1334 -0
  37. absfuyu/logger.py +10 -15
  38. absfuyu/pkg_data/__init__.py +137 -100
  39. absfuyu/pkg_data/deprecated.py +133 -0
  40. absfuyu/sort.py +6 -130
  41. absfuyu/tools/__init__.py +2 -2
  42. absfuyu/tools/checksum.py +33 -22
  43. absfuyu/tools/converter.py +51 -48
  44. absfuyu/{general → tools}/generator.py +17 -42
  45. absfuyu/tools/keygen.py +25 -30
  46. absfuyu/tools/obfuscator.py +246 -112
  47. absfuyu/tools/passwordlib.py +100 -30
  48. absfuyu/tools/shutdownizer.py +68 -47
  49. absfuyu/tools/web.py +4 -11
  50. absfuyu/util/__init__.py +17 -17
  51. absfuyu/util/api.py +10 -15
  52. absfuyu/util/json_method.py +7 -24
  53. absfuyu/util/lunar.py +5 -11
  54. absfuyu/util/path.py +22 -27
  55. absfuyu/util/performance.py +43 -67
  56. absfuyu/util/shorten_number.py +65 -14
  57. absfuyu/util/zipped.py +11 -17
  58. absfuyu/version.py +59 -42
  59. {absfuyu-4.2.0.dist-info → absfuyu-5.0.1.dist-info}/METADATA +41 -14
  60. absfuyu-5.0.1.dist-info/RECORD +68 -0
  61. absfuyu/core.py +0 -57
  62. absfuyu/everything.py +0 -32
  63. absfuyu/extensions/__init__.py +0 -12
  64. absfuyu/extensions/beautiful.py +0 -188
  65. absfuyu/fun/WGS.py +0 -134
  66. absfuyu/general/data_extension.py +0 -1796
  67. absfuyu/tools/stats.py +0 -226
  68. absfuyu/util/pkl.py +0 -67
  69. absfuyu-4.2.0.dist-info/RECORD +0 -59
  70. {absfuyu-4.2.0.dist-info → absfuyu-5.0.1.dist-info}/WHEEL +0 -0
  71. {absfuyu-4.2.0.dist-info → absfuyu-5.0.1.dist-info}/entry_points.txt +0 -0
  72. {absfuyu-4.2.0.dist-info → absfuyu-5.0.1.dist-info}/licenses/LICENSE +0 -0
absfuyu/dxt/strext.py ADDED
@@ -0,0 +1,530 @@
1
+ """
2
+ Absfuyu: Data Extension
3
+ -----------------------
4
+ str extension
5
+
6
+ Version: 5.0.0
7
+ Date updated: 25/02/2025 (dd/mm/yyyy)
8
+ """
9
+
10
+ # Module Package
11
+ # ---------------------------------------------------------------------------
12
+ __all__ = ["Text", "TextAnalyzeDictFormat"]
13
+
14
+
15
+ # Library
16
+ # ---------------------------------------------------------------------------
17
+ import random
18
+ from typing import NotRequired, Self, TypedDict
19
+
20
+ from absfuyu.core import ShowAllMethodsMixin, deprecated, versionadded, versionchanged
21
+ from absfuyu.logger import logger
22
+ from absfuyu.tools.generator import Charset, Generator
23
+ from absfuyu.util import set_min_max
24
+
25
+
26
+ # Class
27
+ # ---------------------------------------------------------------------------
28
+ class TextAnalyzeDictFormat(TypedDict):
29
+ """
30
+ Dict format for ``Text.analyze()`` method
31
+
32
+ Parameters
33
+ ----------
34
+ digit : int
35
+ Number of digit characters
36
+
37
+ uppercase : int
38
+ Number of uppercase characters
39
+
40
+ lowercase : int
41
+ Number of lowercase characters
42
+
43
+ other : int
44
+ Number of other printable characters
45
+
46
+ is_pangram : NotRequired[bool]
47
+ Is a pangram (Not required)
48
+
49
+ is_palindrome : NotRequired[bool]
50
+ Is a palindrome (Not required)
51
+ """
52
+
53
+ digit: int
54
+ uppercase: int
55
+ lowercase: int
56
+ other: int
57
+ is_pangram: NotRequired[bool]
58
+ is_palindrome: NotRequired[bool]
59
+
60
+
61
+ class Text(ShowAllMethodsMixin, str):
62
+ """
63
+ ``str`` extension
64
+ """
65
+
66
+ def divide(self, string_split_size: int = 60) -> list[str]:
67
+ """
68
+ Divide long string into smaller size
69
+
70
+ Parameters
71
+ ----------
72
+ string_split_size : int
73
+ Divide string every ``x`` character
74
+ (Default: ``60``)
75
+
76
+ Returns
77
+ -------
78
+ list[str]
79
+ A list in which each item is a smaller
80
+ string with the size of ``string_split_size``
81
+ (need to be concaternate later)
82
+
83
+
84
+ Example:
85
+ --------
86
+ >>> test = Text("This is an extremely long line of text!")
87
+ >>> test.divide(string_split_size=20)
88
+ ['This is an extremely', ' long line of text!']
89
+ """
90
+ temp = str(self)
91
+ output = []
92
+ while len(temp) != 0:
93
+ output.append(temp[:string_split_size])
94
+ temp = temp[string_split_size:]
95
+ return output
96
+
97
+ def divide_with_variable(
98
+ self,
99
+ split_size: int = 60,
100
+ split_var_len: int = 12,
101
+ custom_var_name: str | None = None,
102
+ ) -> list[str]:
103
+ """
104
+ Divide long string into smaller size,
105
+ then assign a random variable to splited
106
+ string for later use
107
+
108
+ Parameters
109
+ ----------
110
+ split_size : int
111
+ Divide string every ``x`` character
112
+ (Default: ``60``)
113
+
114
+ split_var_len : int
115
+ Length of variable name assigned to each item
116
+ (Default: ``12``)
117
+
118
+ custom_var_name : str
119
+ Custom variable name when join string
120
+
121
+ Returns
122
+ -------
123
+ list[str]
124
+ A list in which each item is a smaller
125
+ string with the size of ``split_size``
126
+ and a way to concaternate them (when using ``print()``)
127
+
128
+
129
+ Example:
130
+ --------
131
+ >>> test = Text("This is an extremely long line of text!")
132
+ >>> test.divide_with_variable(split_size=20)
133
+ [
134
+ "qNTCnmkFPTJg='This is an extremely'",
135
+ "vkmLBUykYYDG=' long line of text!'",
136
+ 'sBoSwEfoxBIH=qNTCnmkFPTJg+vkmLBUykYYDG',
137
+ 'sBoSwEfoxBIH'
138
+ ]
139
+
140
+ >>> test = Text("This is an extremely long line of text!")
141
+ >>> test.divide_with_variable(split_size=20, custom_var_name="test")
142
+ [
143
+ "test1='This is an extremely'",
144
+ "test2=' long line of text!'",
145
+ 'test=test1+test2',
146
+ 'test'
147
+ ]
148
+ """
149
+
150
+ temp = self.divide(split_size)
151
+ output = []
152
+
153
+ # split variable
154
+ splt_len = len(temp)
155
+
156
+ if custom_var_name is None:
157
+ splt_name = Generator.generate_string(
158
+ charset=Charset.ALPHABET, size=split_var_len, times=splt_len + 1
159
+ )
160
+ for i in range(splt_len):
161
+ output.append(f"{splt_name[i]}='{temp[i]}'")
162
+ else:
163
+ for i in range(splt_len):
164
+ output.append(f"{custom_var_name}{i + 1}='{temp[i]}'")
165
+
166
+ # joined variable
167
+ temp = []
168
+ if custom_var_name is None:
169
+ for i in range(splt_len):
170
+ if i == 0:
171
+ temp.append(f"{splt_name[-1]}=")
172
+ if i == splt_len - 1:
173
+ temp.append(f"{splt_name[i]}")
174
+ else:
175
+ temp.append(f"{splt_name[i]}+")
176
+ else:
177
+ for i in range(splt_len):
178
+ if i == 0:
179
+ temp.append(f"{custom_var_name}=")
180
+ if i == splt_len - 1:
181
+ temp.append(f"{custom_var_name}{i + 1}")
182
+ else:
183
+ temp.append(f"{custom_var_name}{i + 1}+")
184
+
185
+ output.append("".join(temp))
186
+ if custom_var_name is None:
187
+ output.append(splt_name[-1])
188
+ else:
189
+ output.append(custom_var_name)
190
+
191
+ return output
192
+
193
+ @versionchanged("3.3.0", reason="Updated functionality")
194
+ def analyze(self, full: bool = False) -> TextAnalyzeDictFormat:
195
+ """
196
+ String analyze (count number of type of character)
197
+
198
+ Parameters
199
+ ----------
200
+ full : bool
201
+ Full analyze when ``True``
202
+ (Default: ``False``)
203
+
204
+ Returns
205
+ -------
206
+ dict | TextAnalyzeDictFormat
207
+ A dictionary contains number of digit character,
208
+ uppercase character, lowercase character, and
209
+ special character
210
+
211
+
212
+ Example:
213
+ --------
214
+ >>> test = Text("Random T3xt!")
215
+ >>> test.analyze()
216
+ {'digit': 1, 'uppercase': 2, 'lowercase': 7, 'other': 2}
217
+ """
218
+
219
+ temp = self
220
+
221
+ detail: TextAnalyzeDictFormat = {
222
+ "digit": 0,
223
+ "uppercase": 0,
224
+ "lowercase": 0,
225
+ "other": 0,
226
+ }
227
+
228
+ for x in temp:
229
+ if ord(x) in range(48, 58): # num
230
+ detail["digit"] += 1
231
+ elif ord(x) in range(65, 91): # cap
232
+ detail["uppercase"] += 1
233
+ elif ord(x) in range(97, 123): # low
234
+ detail["lowercase"] += 1
235
+ else:
236
+ detail["other"] += 1
237
+
238
+ if full:
239
+ detail["is_palindrome"] = self.is_palindrome()
240
+ detail["is_pangram"] = self.is_pangram()
241
+
242
+ return detail
243
+
244
+ def reverse(self) -> Self:
245
+ """
246
+ Reverse the string
247
+
248
+ Returns
249
+ -------
250
+ Text
251
+ Reversed string
252
+
253
+
254
+ Example:
255
+ --------
256
+ >>> test = Text("Hello, World!")
257
+ >>> test.reverse()
258
+ '!dlroW ,olleH'
259
+ """
260
+ return self.__class__(self[::-1])
261
+
262
+ @versionchanged("5.0.0", reason="Add ``custom_alphabet`` parameter")
263
+ def is_pangram(self, custom_alphabet: set[str] | None = None) -> bool:
264
+ """
265
+ Check if string is a pangram
266
+
267
+ A pangram is a unique sentence in which
268
+ every letter of the alphabet is used at least once
269
+
270
+ Parameters
271
+ ----------
272
+ custom_alphabet : set[str] | None, optional
273
+ Custom alphabet to use
274
+ (Default: ``None``)
275
+
276
+ Returns
277
+ -------
278
+ bool
279
+ | ``True`` if string is a pangram
280
+ | ``False`` if string is not a pangram
281
+ """
282
+ text = self
283
+ if custom_alphabet is None:
284
+ alphabet = set("abcdefghijklmnopqrstuvwxyz")
285
+ else:
286
+ alphabet = custom_alphabet
287
+ return not set(alphabet) - set(text.lower())
288
+
289
+ def is_palindrome(self) -> bool:
290
+ """
291
+ Check if string is a palindrome
292
+
293
+ A palindrome is a word, verse, or sentence
294
+ or a number that reads the same backward or forward
295
+
296
+ Returns
297
+ -------
298
+ bool
299
+ | ``True`` if string is a palindrome
300
+ | ``False`` if string is not a palindrome
301
+ """
302
+ text = self
303
+ # Use string slicing [start:end:step]
304
+ return text == text[::-1]
305
+
306
+ def to_hex(self, raw: bool = False) -> str:
307
+ r"""
308
+ Convert string to hex form
309
+
310
+ Parameters
311
+ ----------
312
+ raw : bool
313
+ | ``False``: hex string in the form of ``\x`` (default)
314
+ | ``True``: normal hex string
315
+
316
+ Returns
317
+ -------
318
+ str
319
+ Hexed string
320
+
321
+
322
+ Example:
323
+ --------
324
+ >>> test = Text("Hello, World!")
325
+ >>> test.to_hex()
326
+ '\\x48\\x65\\x6c\\x6c\\x6f\\x2c\\x20\\x57\\x6f\\x72\\x6c\\x64\\x21'
327
+ """
328
+ text = self
329
+
330
+ byte_str = text.encode("utf-8")
331
+ # hex_str = byte_str.hex()
332
+
333
+ if raw:
334
+ return byte_str.hex()
335
+
336
+ temp = byte_str.hex("x")
337
+ return "\\x" + temp.replace("x", "\\x")
338
+
339
+ def random_capslock(self, probability: int = 50) -> Self:
340
+ """
341
+ Randomly capslock letter in string
342
+
343
+ Parameters
344
+ ----------
345
+ probability : int
346
+ Probability in range [0, 100]
347
+ (Default: ``50``)
348
+
349
+ Returns
350
+ -------
351
+ Text
352
+ Random capslocked text
353
+
354
+
355
+ Example:
356
+ --------
357
+ >>> test = Text("This is an extremely long line of text!")
358
+ >>> test.random_capslock()
359
+ 'tHis iS An ExtREmELY loNg liNE oF tExT!'
360
+ """
361
+ probability = int(set_min_max(probability))
362
+ text = self.lower()
363
+
364
+ temp = []
365
+ for x in text:
366
+ if random.randint(1, 100) <= probability:
367
+ x = x.upper()
368
+ temp.append(x)
369
+ logger.debug(temp)
370
+ return self.__class__("".join(temp))
371
+
372
+ @versionchanged("5.0.0", reason="Use ``str.swapcase()``")
373
+ def reverse_capslock(self) -> Self:
374
+ """
375
+ Reverse capslock in string
376
+
377
+ Returns
378
+ -------
379
+ Text
380
+ Reversed capslock ``Text``
381
+
382
+
383
+ Example:
384
+ --------
385
+ >>> test = Text("Foo")
386
+ >>> test.reverse_capslock()
387
+ 'fOO'
388
+ """
389
+ return self.__class__(self.swapcase())
390
+
391
+ def to_list(self) -> list[str]:
392
+ """
393
+ Convert into list
394
+
395
+ Returns
396
+ -------
397
+ list[str]
398
+ List of string
399
+
400
+
401
+ Example:
402
+ --------
403
+ >>> test = Text("test")
404
+ >>> test.to_list()
405
+ ['t', 'e', 's', 't']
406
+ """
407
+ return list(self)
408
+
409
+ @deprecated("5.0.0", reason="Unused")
410
+ def to_listext(self) -> None:
411
+ """Deprecated, will be removed soon"""
412
+ raise NotImplementedError("Deprecated, will be removed soon")
413
+
414
+ @versionadded("3.3.0")
415
+ def count_pattern(self, pattern: str, ignore_capslock: bool = False) -> int:
416
+ """
417
+ Returns how many times ``pattern`` appears in text
418
+
419
+ Parameters
420
+ ----------
421
+ pattern : str
422
+ Pattern to count
423
+
424
+ ignore_capslock : bool
425
+ Ignore the pattern uppercase or lowercase
426
+ (Default: ``False`` - Exact match)
427
+
428
+ Returns
429
+ -------
430
+ int
431
+ How many times pattern appeared
432
+
433
+
434
+ Example:
435
+ --------
436
+ >>> Text("test").count_pattern("t")
437
+ 2
438
+ """
439
+ if len(pattern) > len(self):
440
+ raise ValueError(f"len(<pattern>) must not larger than {len(self)}")
441
+
442
+ temp = str(self)
443
+ if ignore_capslock:
444
+ pattern = pattern.lower()
445
+ temp = temp.lower()
446
+
447
+ out = [
448
+ 1
449
+ for i in range(len(temp) - len(pattern) + 1)
450
+ if temp[i : i + len(pattern)] == pattern
451
+ ]
452
+ return sum(out)
453
+
454
+ @versionadded("3.3.0")
455
+ def hapax(self, strict: bool = False) -> list[str]:
456
+ """
457
+ A hapax legomenon (often abbreviated to hapax)
458
+ is a word which occurs only once in either
459
+ the written record of a language, the works of
460
+ an author, or in a single text.
461
+
462
+ This function returns a list of hapaxes (if any)
463
+ (Lettercase is ignored)
464
+
465
+ Parameters
466
+ ----------
467
+ strict : bool
468
+ Remove all special characters before checking for hapax
469
+ (Default: ``False``)
470
+
471
+ Returns
472
+ -------
473
+ list[str]
474
+ A list of hapaxes
475
+
476
+
477
+ Example:
478
+ --------
479
+ >>> test = Text("A a. a, b c c= C| d d")
480
+ >>> test.hapax()
481
+ ['a', 'a.', 'a,', 'b', 'c', 'c=', 'c|']
482
+
483
+ >>> test.hapax(strict=True)
484
+ ['b']
485
+ """
486
+ word_list: list[str] = self.lower().split()
487
+ if strict:
488
+ remove_characters: list[str] = list(r"\"'.,:;|()[]{}\/!@#$%^&*-_=+?<>`~")
489
+ temp = str(self)
490
+ for x in remove_characters:
491
+ temp = temp.replace(x, "")
492
+ word_list = temp.lower().split()
493
+
494
+ hapaxes = filter(lambda x: word_list.count(x) == 1, word_list)
495
+ return list(hapaxes)
496
+
497
+ @versionadded("5.0.0")
498
+ def shorten(self, shorten_size: int = 60) -> str:
499
+ """
500
+ Shorten long text
501
+
502
+ Parameters
503
+ ----------
504
+ shorten_size : int, optional
505
+ How many characters per line.
506
+ Minimum is ``1``, by default ``60``
507
+
508
+ Returns
509
+ -------
510
+ str
511
+ Shortened text
512
+
513
+
514
+ Example:
515
+ --------
516
+ >>> test = Text("a" * 200)
517
+ >>> test.shorten()
518
+ (
519
+ 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
520
+ 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
521
+ 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
522
+ 'aaaaaaaaaaaaaaaaaaaa'
523
+ )
524
+ """
525
+ shorten_text_list: list[str] = self.divide(
526
+ string_split_size=max(1, shorten_size)
527
+ )
528
+ shorten_text_list = [repr(x) for x in shorten_text_list]
529
+ out = "(\n" + "\n".join(shorten_text_list) + "\n)"
530
+ return out
@@ -0,0 +1,12 @@
1
+ """
2
+ Absfuyu: Extra
3
+ --------------
4
+ Features that require additional libraries
5
+
6
+ Version: 5.0.0
7
+ Date updated: 22/02/2025 (dd/mm/yyyy)
8
+ """
9
+
10
+
11
+ def is_loaded():
12
+ return True