absfuyu 3.4.0__py3-none-any.whl → 4.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.
- absfuyu/__init__.py +1 -1
- absfuyu/cli/do_group.py +51 -2
- absfuyu/config/__init__.py +13 -13
- absfuyu/core.py +18 -16
- absfuyu/extensions/extra/data_analysis.py +74 -28
- absfuyu/fun/__init__.py +24 -23
- absfuyu/fun/tarot.py +6 -7
- absfuyu/game/__init__.py +2 -2
- absfuyu/game/game_stat.py +1 -1
- absfuyu/game/sudoku.py +6 -5
- absfuyu/game/tictactoe.py +4 -4
- absfuyu/general/content.py +7 -7
- absfuyu/general/data_extension.py +44 -63
- absfuyu/general/generator.py +4 -2
- absfuyu/logger.py +2 -2
- absfuyu/pkg_data/__init__.py +13 -20
- absfuyu/tools/checksum.py +56 -0
- absfuyu/tools/converter.py +33 -10
- absfuyu/tools/obfuscator.py +1 -1
- absfuyu/util/__init__.py +13 -14
- absfuyu/util/api.py +7 -7
- absfuyu/util/json_method.py +9 -9
- absfuyu/util/lunar.py +7 -8
- absfuyu/util/path.py +23 -21
- absfuyu/util/performance.py +8 -8
- absfuyu/util/shorten_number.py +228 -0
- absfuyu/util/zipped.py +18 -6
- {absfuyu-3.4.0.dist-info → absfuyu-4.1.0.dist-info}/METADATA +6 -9
- absfuyu-4.1.0.dist-info/RECORD +61 -0
- {absfuyu-3.4.0.dist-info → absfuyu-4.1.0.dist-info}/WHEEL +1 -1
- {absfuyu-3.4.0.dist-info → absfuyu-4.1.0.dist-info}/licenses/LICENSE +21 -21
- absfuyu-3.4.0.dist-info/RECORD +0 -59
- {absfuyu-3.4.0.dist-info → absfuyu-4.1.0.dist-info}/entry_points.txt +0 -0
absfuyu/game/sudoku.py
CHANGED
|
@@ -3,8 +3,8 @@ Game: Sudoku
|
|
|
3
3
|
------------
|
|
4
4
|
Sudoku 9x9 Solver
|
|
5
5
|
|
|
6
|
-
Version: 1.0.
|
|
7
|
-
Date updated:
|
|
6
|
+
Version: 1.0.3
|
|
7
|
+
Date updated: 15/11/2024 (dd/mm/yyyy)
|
|
8
8
|
|
|
9
9
|
Credit:
|
|
10
10
|
-------
|
|
@@ -15,11 +15,12 @@ Credit:
|
|
|
15
15
|
__all__ = ["Sudoku"]
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
from typing import
|
|
18
|
+
from typing import Literal
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
class Sudoku:
|
|
22
|
-
|
|
22
|
+
|
|
23
|
+
def __init__(self, sudoku_data: list[list[int]]) -> None:
|
|
23
24
|
self.data = sudoku_data
|
|
24
25
|
# self._original = sudoku_data # Make backup
|
|
25
26
|
self._row_len = len(self.data)
|
|
@@ -194,7 +195,7 @@ class Sudoku:
|
|
|
194
195
|
# Return None when there is no empty cell
|
|
195
196
|
return None
|
|
196
197
|
|
|
197
|
-
def _is_valid(self, number: int, position:
|
|
198
|
+
def _is_valid(self, number: int, position: tuple[int, int]) -> bool:
|
|
198
199
|
"""
|
|
199
200
|
Check valid number value in row, column, box
|
|
200
201
|
"""
|
absfuyu/game/tictactoe.py
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
Game: Tic Tac Toe
|
|
3
3
|
-----------------
|
|
4
4
|
|
|
5
|
-
Version: 2.0.
|
|
6
|
-
Date updated:
|
|
5
|
+
Version: 2.0.4
|
|
6
|
+
Date updated: 15/11/2024 (dd/mm/yyyy)
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
9
|
__all__ = ["TicTacToe", "GameMode"]
|
|
@@ -11,11 +11,11 @@ __all__ = ["TicTacToe", "GameMode"]
|
|
|
11
11
|
|
|
12
12
|
import random
|
|
13
13
|
import time
|
|
14
|
-
from typing import
|
|
14
|
+
from typing import Literal, NamedTuple
|
|
15
15
|
|
|
16
16
|
from absfuyu.core import CLITextColor
|
|
17
17
|
|
|
18
|
-
BoardGame =
|
|
18
|
+
BoardGame = list[list[str]]
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
class Pos(NamedTuple):
|
absfuyu/general/content.py
CHANGED
|
@@ -427,12 +427,12 @@ class ContentLoader:
|
|
|
427
427
|
self.tag_dictionary = tag_dictionary
|
|
428
428
|
|
|
429
429
|
# symbol stuff
|
|
430
|
-
assert (
|
|
431
|
-
comment_symbol
|
|
432
|
-
)
|
|
433
|
-
assert (
|
|
434
|
-
tag_separate_symbol
|
|
435
|
-
)
|
|
430
|
+
assert comment_symbol != split_symbol, (
|
|
431
|
+
"comment_symbol and split_symbol should have different values"
|
|
432
|
+
)
|
|
433
|
+
assert tag_separate_symbol != split_symbol, (
|
|
434
|
+
"tag_separate_symbol and split_symbol should have different values"
|
|
435
|
+
)
|
|
436
436
|
self.comment_symbol: str = comment_symbol
|
|
437
437
|
self.split_symbol: str = split_symbol
|
|
438
438
|
self.tag_separate_symbol: str = tag_separate_symbol
|
|
@@ -485,7 +485,7 @@ class ContentLoader:
|
|
|
485
485
|
if x.startswith(self.comment_symbol) or len(x) == 0:
|
|
486
486
|
continue # skip comment and empty lines
|
|
487
487
|
logger.debug(
|
|
488
|
-
f"### Loop {i+1} #####################################################################"
|
|
488
|
+
f"### Loop {i + 1} #####################################################################"
|
|
489
489
|
)
|
|
490
490
|
|
|
491
491
|
temp = x.split(self.split_symbol)
|
|
@@ -3,8 +3,8 @@ Absfuyu: Data extension
|
|
|
3
3
|
-----------------------
|
|
4
4
|
Extension for data type such as ``list``, ``str``, ``dict``, ...
|
|
5
5
|
|
|
6
|
-
Version: 1.15.
|
|
7
|
-
Date updated:
|
|
6
|
+
Version: 1.15.2
|
|
7
|
+
Date updated: 06/01/2025 (dd/mm/yyyy)
|
|
8
8
|
|
|
9
9
|
Features:
|
|
10
10
|
---------
|
|
@@ -47,23 +47,7 @@ import operator
|
|
|
47
47
|
import random
|
|
48
48
|
from collections import Counter
|
|
49
49
|
from itertools import accumulate, chain, groupby
|
|
50
|
-
from
|
|
51
|
-
from typing import (
|
|
52
|
-
Any,
|
|
53
|
-
Callable,
|
|
54
|
-
Dict,
|
|
55
|
-
List,
|
|
56
|
-
NamedTuple,
|
|
57
|
-
Optional,
|
|
58
|
-
Tuple,
|
|
59
|
-
TypedDict,
|
|
60
|
-
Union,
|
|
61
|
-
)
|
|
62
|
-
|
|
63
|
-
if _python_version.minor >= 11:
|
|
64
|
-
from typing import NotRequired, Self
|
|
65
|
-
else:
|
|
66
|
-
from typing_extensions import NotRequired, Self # type: ignore
|
|
50
|
+
from typing import Any, Callable, NamedTuple, NotRequired, Self, TypedDict, Union
|
|
67
51
|
|
|
68
52
|
from deprecated.sphinx import versionadded, versionchanged
|
|
69
53
|
|
|
@@ -74,7 +58,7 @@ from absfuyu.util import set_min, set_min_max
|
|
|
74
58
|
|
|
75
59
|
# Function
|
|
76
60
|
###########################################################################
|
|
77
|
-
def _dict_bool(dict_object: dict, option: bool) ->
|
|
61
|
+
def _dict_bool(dict_object: dict, option: bool) -> dict | None:
|
|
78
62
|
"""
|
|
79
63
|
Support function DictBool class
|
|
80
64
|
"""
|
|
@@ -93,7 +77,7 @@ def _dict_bool(dict_object: dict, option: bool) -> Optional[dict]:
|
|
|
93
77
|
class Pow:
|
|
94
78
|
"""Number power by a number"""
|
|
95
79
|
|
|
96
|
-
def __init__(self, number:
|
|
80
|
+
def __init__(self, number: int | float, power_by: int | float) -> None:
|
|
97
81
|
self.number = number
|
|
98
82
|
self.power_by = power_by
|
|
99
83
|
|
|
@@ -107,7 +91,7 @@ class Pow:
|
|
|
107
91
|
def __repr__(self) -> str:
|
|
108
92
|
return self.__str__()
|
|
109
93
|
|
|
110
|
-
def to_list(self) ->
|
|
94
|
+
def to_list(self) -> list[int | float]:
|
|
111
95
|
"""
|
|
112
96
|
Convert into list
|
|
113
97
|
|
|
@@ -132,7 +116,7 @@ class ListREPR(list):
|
|
|
132
116
|
return _compress_list_for_print(self, 9)
|
|
133
117
|
|
|
134
118
|
|
|
135
|
-
class ListNoDunder(
|
|
119
|
+
class ListNoDunder(list[str]):
|
|
136
120
|
"""Use with ``object.__dir__()``"""
|
|
137
121
|
|
|
138
122
|
def __repr__(self) -> str:
|
|
@@ -140,7 +124,7 @@ class ListNoDunder(List[str]):
|
|
|
140
124
|
return out.__repr__()
|
|
141
125
|
|
|
142
126
|
|
|
143
|
-
class DictBoolTrue(
|
|
127
|
+
class DictBoolTrue(dict[Any, bool]):
|
|
144
128
|
"""Only show items when ``values == True`` in ``__repr__()``"""
|
|
145
129
|
|
|
146
130
|
def __repr__(self) -> str:
|
|
@@ -148,7 +132,7 @@ class DictBoolTrue(Dict[Any, bool]):
|
|
|
148
132
|
return _dict_bool(temp, True).__repr__()
|
|
149
133
|
|
|
150
134
|
|
|
151
|
-
class DictBoolFalse(
|
|
135
|
+
class DictBoolFalse(dict[Any, bool]):
|
|
152
136
|
"""Only show items when ``values == False`` in ``__repr__()``"""
|
|
153
137
|
|
|
154
138
|
def __repr__(self) -> str:
|
|
@@ -206,8 +190,8 @@ class DictAnalyzeResult(NamedTuple):
|
|
|
206
190
|
Result for ``DictExt.analyze()``
|
|
207
191
|
"""
|
|
208
192
|
|
|
209
|
-
max_value:
|
|
210
|
-
min_value:
|
|
193
|
+
max_value: int | float
|
|
194
|
+
min_value: int | float
|
|
211
195
|
max_list: list
|
|
212
196
|
min_list: list
|
|
213
197
|
|
|
@@ -220,7 +204,7 @@ class Text(str):
|
|
|
220
204
|
``str`` extension
|
|
221
205
|
"""
|
|
222
206
|
|
|
223
|
-
def divide(self, string_split_size: int = 60) ->
|
|
207
|
+
def divide(self, string_split_size: int = 60) -> list[str]:
|
|
224
208
|
"""
|
|
225
209
|
Divide long string into smaller size
|
|
226
210
|
|
|
@@ -255,8 +239,8 @@ class Text(str):
|
|
|
255
239
|
self,
|
|
256
240
|
split_size: int = 60,
|
|
257
241
|
split_var_len: int = 12,
|
|
258
|
-
custom_var_name:
|
|
259
|
-
) ->
|
|
242
|
+
custom_var_name: str | None = None,
|
|
243
|
+
) -> list[str]:
|
|
260
244
|
"""
|
|
261
245
|
Divide long string into smaller size,
|
|
262
246
|
then assign a random variable to splited
|
|
@@ -318,7 +302,7 @@ class Text(str):
|
|
|
318
302
|
output.append(f"{splt_name[i]}='{temp[i]}'")
|
|
319
303
|
else:
|
|
320
304
|
for i in range(splt_len):
|
|
321
|
-
output.append(f"{custom_var_name}{i+1}='{temp[i]}'")
|
|
305
|
+
output.append(f"{custom_var_name}{i + 1}='{temp[i]}'")
|
|
322
306
|
|
|
323
307
|
# joined variable
|
|
324
308
|
temp = []
|
|
@@ -335,9 +319,9 @@ class Text(str):
|
|
|
335
319
|
if i == 0:
|
|
336
320
|
temp.append(f"{custom_var_name}=")
|
|
337
321
|
if i == splt_len - 1:
|
|
338
|
-
temp.append(f"{custom_var_name}{i+1}")
|
|
322
|
+
temp.append(f"{custom_var_name}{i + 1}")
|
|
339
323
|
else:
|
|
340
|
-
temp.append(f"{custom_var_name}{i+1}+")
|
|
324
|
+
temp.append(f"{custom_var_name}{i + 1}+")
|
|
341
325
|
|
|
342
326
|
output.append("".join(temp))
|
|
343
327
|
if custom_var_name is None:
|
|
@@ -546,7 +530,7 @@ class Text(str):
|
|
|
546
530
|
temp[i] = x.upper()
|
|
547
531
|
return self.__class__("".join(temp))
|
|
548
532
|
|
|
549
|
-
def to_list(self) ->
|
|
533
|
+
def to_list(self) -> list[str]:
|
|
550
534
|
"""
|
|
551
535
|
Convert into list
|
|
552
536
|
|
|
@@ -625,7 +609,7 @@ class Text(str):
|
|
|
625
609
|
return sum(out)
|
|
626
610
|
|
|
627
611
|
@versionadded(version="3.3.0")
|
|
628
|
-
def hapax(self, strict: bool = False) ->
|
|
612
|
+
def hapax(self, strict: bool = False) -> list[str]:
|
|
629
613
|
"""
|
|
630
614
|
A hapax legomenon (often abbreviated to hapax)
|
|
631
615
|
is a word which occurs only once in either
|
|
@@ -656,9 +640,9 @@ class Text(str):
|
|
|
656
640
|
>>> test.hapax(strict=True)
|
|
657
641
|
['b']
|
|
658
642
|
"""
|
|
659
|
-
word_list:
|
|
643
|
+
word_list: list[str] = self.lower().split()
|
|
660
644
|
if strict:
|
|
661
|
-
remove_characters:
|
|
645
|
+
remove_characters: list[str] = list(r"\"'.,:;|()[]{}\/!@#$%^&*-_=+?<>`~")
|
|
662
646
|
temp = str(self)
|
|
663
647
|
for x in remove_characters:
|
|
664
648
|
temp = temp.replace(x, "")
|
|
@@ -845,7 +829,7 @@ class IntNumber(int):
|
|
|
845
829
|
|
|
846
830
|
else:
|
|
847
831
|
# Faster way to check
|
|
848
|
-
perfect_number_index:
|
|
832
|
+
perfect_number_index: list[int] = [
|
|
849
833
|
61,
|
|
850
834
|
89,
|
|
851
835
|
107,
|
|
@@ -982,7 +966,7 @@ class IntNumber(int):
|
|
|
982
966
|
return self.is_palindromic() and self.is_prime()
|
|
983
967
|
|
|
984
968
|
# calculation stuff
|
|
985
|
-
@versionchanged(version="
|
|
969
|
+
@versionchanged(version="4.0.0", reason="Update")
|
|
986
970
|
def lcm(self, with_number: int) -> Self:
|
|
987
971
|
"""
|
|
988
972
|
Least common multiple of ``self`` and ``with_number``
|
|
@@ -1004,10 +988,7 @@ class IntNumber(int):
|
|
|
1004
988
|
>>> test.lcm(5)
|
|
1005
989
|
510
|
|
1006
990
|
"""
|
|
1007
|
-
|
|
1008
|
-
return self.__class__(math.lcm(self, with_number))
|
|
1009
|
-
except AttributeError: # Python < 3.9
|
|
1010
|
-
return self.__class__((self * with_number) // math.gcd(self, with_number))
|
|
991
|
+
return self.__class__(math.lcm(self, with_number))
|
|
1011
992
|
|
|
1012
993
|
@versionchanged(version="3.3.0", reason="Fix bug")
|
|
1013
994
|
def gcd(self, with_number: int) -> Self:
|
|
@@ -1072,7 +1053,7 @@ class IntNumber(int):
|
|
|
1072
1053
|
logger.debug(f"Sum after loop: {number}")
|
|
1073
1054
|
return self.__class__(number)
|
|
1074
1055
|
|
|
1075
|
-
def divisible_list(self, short_form: bool = True) ->
|
|
1056
|
+
def divisible_list(self, short_form: bool = True) -> list[int]:
|
|
1076
1057
|
"""
|
|
1077
1058
|
A list of divisible number
|
|
1078
1059
|
|
|
@@ -1106,7 +1087,7 @@ class IntNumber(int):
|
|
|
1106
1087
|
# return ListREPR(divi_list) ## FIX LATER
|
|
1107
1088
|
return divi_list
|
|
1108
1089
|
|
|
1109
|
-
def prime_factor(self, short_form: bool = True) -> Union[
|
|
1090
|
+
def prime_factor(self, short_form: bool = True) -> Union[list[int], list[Pow]]:
|
|
1110
1091
|
"""
|
|
1111
1092
|
Prime factor
|
|
1112
1093
|
|
|
@@ -1156,7 +1137,7 @@ class IntNumber(int):
|
|
|
1156
1137
|
return factors
|
|
1157
1138
|
|
|
1158
1139
|
# analyze
|
|
1159
|
-
def analyze(self, short_form: bool = True) ->
|
|
1140
|
+
def analyze(self, short_form: bool = True) -> dict[str, dict[str, Any]]:
|
|
1160
1141
|
"""
|
|
1161
1142
|
Analyze the number with almost all ``IntNumber`` method
|
|
1162
1143
|
|
|
@@ -1236,7 +1217,7 @@ class ListExt(list):
|
|
|
1236
1217
|
>>> test.stringify()
|
|
1237
1218
|
['1', '1', '1', '2', '2', '3']
|
|
1238
1219
|
"""
|
|
1239
|
-
return
|
|
1220
|
+
return self.__class__(map(str, self))
|
|
1240
1221
|
|
|
1241
1222
|
def head(self, number_of_items: int = 5) -> list:
|
|
1242
1223
|
"""
|
|
@@ -1318,9 +1299,9 @@ class ListExt(list):
|
|
|
1318
1299
|
def freq(
|
|
1319
1300
|
self,
|
|
1320
1301
|
sort: bool = False,
|
|
1321
|
-
num_of_first_char:
|
|
1302
|
+
num_of_first_char: int | None = None,
|
|
1322
1303
|
appear_increment: bool = False,
|
|
1323
|
-
) -> Union[dict,
|
|
1304
|
+
) -> Union[dict, list[int]]:
|
|
1324
1305
|
"""
|
|
1325
1306
|
Find frequency of each item in list
|
|
1326
1307
|
|
|
@@ -1383,7 +1364,7 @@ class ListExt(list):
|
|
|
1383
1364
|
logger.debug(times_appear)
|
|
1384
1365
|
|
|
1385
1366
|
if appear_increment:
|
|
1386
|
-
times_appear_increment:
|
|
1367
|
+
times_appear_increment: list[int] = list(
|
|
1387
1368
|
accumulate(times_appear.values(), operator.add)
|
|
1388
1369
|
)
|
|
1389
1370
|
logger.debug(times_appear_increment)
|
|
@@ -1391,7 +1372,7 @@ class ListExt(list):
|
|
|
1391
1372
|
else:
|
|
1392
1373
|
return times_appear
|
|
1393
1374
|
|
|
1394
|
-
def slice_points(self, points: list) ->
|
|
1375
|
+
def slice_points(self, points: list) -> list[list]:
|
|
1395
1376
|
"""
|
|
1396
1377
|
Slices a list at specific indices into constituent lists.
|
|
1397
1378
|
|
|
@@ -1474,7 +1455,7 @@ class ListExt(list):
|
|
|
1474
1455
|
>>> test.len_items()
|
|
1475
1456
|
[3, 3, 5]
|
|
1476
1457
|
"""
|
|
1477
|
-
out =
|
|
1458
|
+
out = self.__class__([len(str(x)) for x in self])
|
|
1478
1459
|
# out = ListExt(map(lambda x: len(str(x)), self))
|
|
1479
1460
|
logger.debug(out)
|
|
1480
1461
|
return out
|
|
@@ -1566,13 +1547,13 @@ class ListExt(list):
|
|
|
1566
1547
|
return self.__class__([list(g) for _, g in temp])
|
|
1567
1548
|
|
|
1568
1549
|
@staticmethod
|
|
1569
|
-
def _group_by_unique(iterable: list) ->
|
|
1550
|
+
def _group_by_unique(iterable: list) -> list[list]:
|
|
1570
1551
|
"""
|
|
1571
1552
|
Static method for ``group_by_unique``
|
|
1572
1553
|
"""
|
|
1573
1554
|
return list([list(g) for _, g in groupby(iterable)])
|
|
1574
1555
|
|
|
1575
|
-
def group_by_pair_value(self, max_loop: int = 3) ->
|
|
1556
|
+
def group_by_pair_value(self, max_loop: int = 3) -> list[list]:
|
|
1576
1557
|
"""
|
|
1577
1558
|
Assume each ``list`` in ``list`` is a pair value,
|
|
1578
1559
|
returns a ``list`` contain all paired value
|
|
@@ -1607,7 +1588,7 @@ class ListExt(list):
|
|
|
1607
1588
|
|
|
1608
1589
|
# Init loop
|
|
1609
1590
|
for _ in range(int(set_min(max_loop, min_value=3))):
|
|
1610
|
-
temp:
|
|
1591
|
+
temp: dict[Any, list] = {}
|
|
1611
1592
|
# Make dict{key: all `item` that contains `key`}
|
|
1612
1593
|
for item in iter:
|
|
1613
1594
|
for x in item:
|
|
@@ -1641,10 +1622,10 @@ class ListExt(list):
|
|
|
1641
1622
|
['test', 'test', 'test', 'test']
|
|
1642
1623
|
"""
|
|
1643
1624
|
try:
|
|
1644
|
-
return
|
|
1625
|
+
return self.__class__(chain(*self))
|
|
1645
1626
|
except Exception:
|
|
1646
1627
|
temp = list(map(lambda x: x if isinstance(x, list) else [x], self))
|
|
1647
|
-
return
|
|
1628
|
+
return self.__class__(chain(*temp))
|
|
1648
1629
|
|
|
1649
1630
|
def numbering(self, start: int = 0) -> Self:
|
|
1650
1631
|
"""
|
|
@@ -1670,10 +1651,10 @@ class ListExt(list):
|
|
|
1670
1651
|
[(0, 9), (1, 9), (2, 9)]
|
|
1671
1652
|
"""
|
|
1672
1653
|
start = int(set_min(start, min_value=0))
|
|
1673
|
-
return
|
|
1654
|
+
return self.__class__(enumerate(self, start=start))
|
|
1674
1655
|
|
|
1675
1656
|
@staticmethod
|
|
1676
|
-
def _numbering(iterable: list, start: int = 0) ->
|
|
1657
|
+
def _numbering(iterable: list, start: int = 0) -> list[tuple[int, Any]]:
|
|
1677
1658
|
"""
|
|
1678
1659
|
Static method for ``numbering``
|
|
1679
1660
|
"""
|
|
@@ -1717,8 +1698,8 @@ class DictExt(dict):
|
|
|
1717
1698
|
try:
|
|
1718
1699
|
dct: dict = self.copy()
|
|
1719
1700
|
|
|
1720
|
-
max_val:
|
|
1721
|
-
min_val:
|
|
1701
|
+
max_val: int | float = max(list(dct.values()))
|
|
1702
|
+
min_val: int | float = min(list(dct.values()))
|
|
1722
1703
|
max_list = []
|
|
1723
1704
|
min_list = []
|
|
1724
1705
|
|
|
@@ -1798,8 +1779,8 @@ class DictExt(dict):
|
|
|
1798
1779
|
@versionadded(version="3.4.0")
|
|
1799
1780
|
def aggregate(
|
|
1800
1781
|
self,
|
|
1801
|
-
other_dict:
|
|
1802
|
-
default_value:
|
|
1782
|
+
other_dict: dict[Any, int | float],
|
|
1783
|
+
default_value: int | float = 0,
|
|
1803
1784
|
) -> Self:
|
|
1804
1785
|
"""Dict with value type int or float"""
|
|
1805
1786
|
out = {
|
absfuyu/general/generator.py
CHANGED
|
@@ -156,7 +156,9 @@ class Generator:
|
|
|
156
156
|
|
|
157
157
|
while count < times:
|
|
158
158
|
s = "".join(choice(char_lst) for _ in range(size))
|
|
159
|
-
logger.debug(
|
|
159
|
+
logger.debug(
|
|
160
|
+
f"Time generated: {count + 1}. Remaining: {times - count - 1}. {s}"
|
|
161
|
+
)
|
|
160
162
|
if not unique:
|
|
161
163
|
unique_string.append(s)
|
|
162
164
|
count += 1
|
|
@@ -274,7 +276,7 @@ class Generator:
|
|
|
274
276
|
if num[i] >= 10: # type: ignore
|
|
275
277
|
num[i] -= 9 # type: ignore
|
|
276
278
|
sum += num[i] # type: ignore
|
|
277
|
-
logger.debug(f"Loop {i+1}: {num[i]}, {sum}")
|
|
279
|
+
logger.debug(f"Loop {i + 1}: {num[i]}, {sum}")
|
|
278
280
|
|
|
279
281
|
out = (10 - (sum % 10)) % 10
|
|
280
282
|
logger.debug(f"Output: {out}")
|
absfuyu/logger.py
CHANGED
|
@@ -100,7 +100,7 @@ def _compress_list_for_print(iterable: list, max_visible: Optional[int] = 5) ->
|
|
|
100
100
|
# temp = [iterable[:cut_idx_1], ["..."], iterable[len(iterable)-cut_idx_2:]]
|
|
101
101
|
# out = list(chain.from_iterable(temp))
|
|
102
102
|
# out = [*iterable[:cut_idx_1], "...", *iterable[len(iterable)-cut_idx_2:]] # Version 2
|
|
103
|
-
out = f"{str(iterable[:cut_idx_1])[:-1]}, ...,{str(iterable[len(iterable)-cut_idx_2:])[1:]}" # Version 3
|
|
103
|
+
out = f"{str(iterable[:cut_idx_1])[:-1]}, ...,{str(iterable[len(iterable) - cut_idx_2 :])[1:]}" # Version 3
|
|
104
104
|
# logger.debug(out)
|
|
105
105
|
return f"{out} [Len: {len(iterable)}]"
|
|
106
106
|
|
|
@@ -123,7 +123,7 @@ def _compress_string_for_print(text: str, max_visible: Optional[int] = 120) -> s
|
|
|
123
123
|
return str(text)
|
|
124
124
|
else:
|
|
125
125
|
cut_idx = math.floor((max_visible - 3) / 2)
|
|
126
|
-
temp = f"{text[:cut_idx]}...{text[len(text)-cut_idx:]}"
|
|
126
|
+
temp = f"{text[:cut_idx]}...{text[len(text) - cut_idx :]}"
|
|
127
127
|
return f"{temp} [Len: {len(text)}]"
|
|
128
128
|
|
|
129
129
|
|
absfuyu/pkg_data/__init__.py
CHANGED
|
@@ -3,8 +3,8 @@ Absfuyu: Package data
|
|
|
3
3
|
---------------------
|
|
4
4
|
Load package data
|
|
5
5
|
|
|
6
|
-
Version: 2.2.
|
|
7
|
-
Date updated:
|
|
6
|
+
Version: 2.2.3
|
|
7
|
+
Date updated: 14/11/2024 (dd/mm/yyyy)
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
# Module level
|
|
@@ -16,18 +16,8 @@ __all__ = ["PkgData"]
|
|
|
16
16
|
###########################################################################
|
|
17
17
|
import zlib
|
|
18
18
|
from ast import literal_eval
|
|
19
|
-
from importlib.resources import read_binary
|
|
19
|
+
from importlib.resources import files, read_binary
|
|
20
20
|
from pathlib import Path
|
|
21
|
-
from sys import version_info as _python_version
|
|
22
|
-
from typing import List, Union
|
|
23
|
-
|
|
24
|
-
if _python_version.minor >= 10:
|
|
25
|
-
from importlib.resources import files
|
|
26
|
-
else:
|
|
27
|
-
try:
|
|
28
|
-
from importlib_resources import files # type: ignore
|
|
29
|
-
except Exception:
|
|
30
|
-
raise ImportError("Please install importlib-resources") # noqa: B904
|
|
31
21
|
|
|
32
22
|
from absfuyu.core import DATA_PATH
|
|
33
23
|
from absfuyu.logger import logger
|
|
@@ -61,7 +51,7 @@ class PkgData:
|
|
|
61
51
|
def __repr__(self) -> str:
|
|
62
52
|
return self.__str__()
|
|
63
53
|
|
|
64
|
-
def _make_dat(self, data: str, name:
|
|
54
|
+
def _make_dat(self, data: str, name: str | Path):
|
|
65
55
|
"""
|
|
66
56
|
data: string data
|
|
67
57
|
name: name and location of the data
|
|
@@ -90,14 +80,14 @@ class PkgData:
|
|
|
90
80
|
|
|
91
81
|
:param new_data: Data to be updated
|
|
92
82
|
"""
|
|
93
|
-
self._make_dat(data=new_data, name=DATA_PATH.joinpath(self.name))
|
|
83
|
+
self._make_dat(data=new_data, name=DATA_PATH.joinpath(self.name)) # type:ignore
|
|
94
84
|
logger.debug("Data updated")
|
|
95
85
|
|
|
96
86
|
|
|
97
87
|
class _ManagePkgData:
|
|
98
88
|
"""Manage this package data"""
|
|
99
89
|
|
|
100
|
-
def __init__(self, pkg_data_loc:
|
|
90
|
+
def __init__(self, pkg_data_loc: str | Path) -> None:
|
|
101
91
|
"""
|
|
102
92
|
pkg_data_loc: Package data location
|
|
103
93
|
"""
|
|
@@ -109,7 +99,7 @@ class _ManagePkgData:
|
|
|
109
99
|
def __repr__(self) -> str:
|
|
110
100
|
return self.__str__()
|
|
111
101
|
|
|
112
|
-
def get_data_list(self, *, pattern: str = "*") ->
|
|
102
|
+
def get_data_list(self, *, pattern: str = "*") -> list[Path]:
|
|
113
103
|
"""Get a list of data available"""
|
|
114
104
|
excludes = [
|
|
115
105
|
x for x in self.data_loc.glob("*.[pP][yY]")
|
|
@@ -119,7 +109,7 @@ class _ManagePkgData:
|
|
|
119
109
|
]
|
|
120
110
|
|
|
121
111
|
@property
|
|
122
|
-
def data_list(self) ->
|
|
112
|
+
def data_list(self) -> list[str]:
|
|
123
113
|
"""List of available data"""
|
|
124
114
|
return [x.name for x in self.get_data_list()]
|
|
125
115
|
|
|
@@ -135,7 +125,10 @@ class _ManagePkgData:
|
|
|
135
125
|
for data_name, data_link in _EXTERNAL_DATA.items():
|
|
136
126
|
logger.debug(f"Downloading {data_name}...")
|
|
137
127
|
data = APIRequest(data_link, encoding="utf-8")
|
|
138
|
-
data.fetch_data(
|
|
128
|
+
data.fetch_data(
|
|
129
|
+
update=True,
|
|
130
|
+
json_cache=DATA_PATH.joinpath(data_name), # type:ignore
|
|
131
|
+
)
|
|
139
132
|
logger.debug(f"Downloading {data_name}...DONE")
|
|
140
133
|
logger.debug("Downloading data...DONE")
|
|
141
134
|
except Exception:
|
|
@@ -147,7 +140,7 @@ class _ManagePkgData:
|
|
|
147
140
|
x.unlink()
|
|
148
141
|
|
|
149
142
|
|
|
150
|
-
PACKAGE_DATA = _ManagePkgData(DATA_PATH)
|
|
143
|
+
PACKAGE_DATA = _ManagePkgData(DATA_PATH) # type:ignore
|
|
151
144
|
|
|
152
145
|
|
|
153
146
|
# Run
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Absufyu: Checksum
|
|
3
|
+
-----------------
|
|
4
|
+
Check MD5, SHA256, ...
|
|
5
|
+
|
|
6
|
+
Version: 1.0.0
|
|
7
|
+
Date updated: 01/02/2025 (dd/mm/yyyy)
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
# Module level
|
|
11
|
+
###########################################################################
|
|
12
|
+
__all__ = ["checksum_operation"]
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# Library
|
|
16
|
+
###########################################################################
|
|
17
|
+
import hashlib
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
from typing import Literal
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# Function
|
|
23
|
+
###########################################################################
|
|
24
|
+
def checksum_operation(
|
|
25
|
+
file: Path | str,
|
|
26
|
+
hash_mode: str | Literal["md5", "sha1", "sha256", "sha512"] = "sha256",
|
|
27
|
+
) -> str:
|
|
28
|
+
"""This performs checksum"""
|
|
29
|
+
if hash_mode.lower() == "md5":
|
|
30
|
+
hash_engine = hashlib.md5()
|
|
31
|
+
elif hash_mode.lower() == "sha1":
|
|
32
|
+
hash_engine = hashlib.sha1()
|
|
33
|
+
elif hash_mode.lower() == "sha256":
|
|
34
|
+
hash_engine = hashlib.sha256()
|
|
35
|
+
elif hash_mode.lower() == "sha512":
|
|
36
|
+
hash_engine = hashlib.sha512()
|
|
37
|
+
else:
|
|
38
|
+
hash_engine = hashlib.md5()
|
|
39
|
+
|
|
40
|
+
with open(Path(file), "rb") as f:
|
|
41
|
+
# Read and hash the file in 4K chunks. Reading the whole
|
|
42
|
+
# file at once might consume a lot of memory if it is
|
|
43
|
+
# large.
|
|
44
|
+
while True:
|
|
45
|
+
data = f.read(4096)
|
|
46
|
+
if len(data) == 0:
|
|
47
|
+
break
|
|
48
|
+
else:
|
|
49
|
+
hash_engine.update(data)
|
|
50
|
+
return hash_engine.hexdigest()
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
# Run
|
|
54
|
+
###########################################################################
|
|
55
|
+
if __name__ == "__main__":
|
|
56
|
+
pass
|