absfuyu 5.0.0__py3-none-any.whl → 6.1.2__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 +5 -3
- absfuyu/__main__.py +3 -3
- absfuyu/cli/__init__.py +13 -2
- absfuyu/cli/audio_group.py +98 -0
- absfuyu/cli/color.py +30 -14
- absfuyu/cli/config_group.py +9 -2
- absfuyu/cli/do_group.py +23 -6
- absfuyu/cli/game_group.py +27 -2
- absfuyu/cli/tool_group.py +81 -11
- absfuyu/config/__init__.py +3 -3
- absfuyu/core/__init__.py +12 -8
- absfuyu/core/baseclass.py +929 -96
- absfuyu/core/baseclass2.py +44 -3
- absfuyu/core/decorator.py +70 -4
- absfuyu/core/docstring.py +64 -41
- absfuyu/core/dummy_cli.py +3 -3
- absfuyu/core/dummy_func.py +19 -6
- absfuyu/dxt/__init__.py +2 -2
- absfuyu/dxt/base_type.py +93 -0
- absfuyu/dxt/dictext.py +204 -16
- absfuyu/dxt/dxt_support.py +2 -2
- absfuyu/dxt/intext.py +151 -34
- absfuyu/dxt/listext.py +969 -127
- absfuyu/dxt/strext.py +77 -17
- absfuyu/extra/__init__.py +2 -2
- absfuyu/extra/audio/__init__.py +8 -0
- absfuyu/extra/audio/_util.py +57 -0
- absfuyu/extra/audio/convert.py +192 -0
- absfuyu/extra/audio/lossless.py +281 -0
- absfuyu/extra/beautiful.py +3 -2
- absfuyu/extra/da/__init__.py +72 -0
- absfuyu/extra/da/dadf.py +1600 -0
- absfuyu/extra/da/dadf_base.py +186 -0
- absfuyu/extra/da/df_func.py +181 -0
- absfuyu/extra/da/mplt.py +219 -0
- absfuyu/extra/ggapi/__init__.py +8 -0
- absfuyu/extra/ggapi/gdrive.py +223 -0
- absfuyu/extra/ggapi/glicense.py +148 -0
- absfuyu/extra/ggapi/glicense_df.py +186 -0
- absfuyu/extra/ggapi/gsheet.py +88 -0
- absfuyu/extra/img/__init__.py +30 -0
- absfuyu/extra/img/converter.py +402 -0
- absfuyu/extra/img/dup_check.py +291 -0
- absfuyu/extra/pdf.py +87 -0
- absfuyu/extra/rclone.py +253 -0
- absfuyu/extra/xml.py +90 -0
- absfuyu/fun/__init__.py +7 -20
- absfuyu/fun/rubik.py +442 -0
- absfuyu/fun/tarot.py +2 -2
- absfuyu/game/__init__.py +2 -2
- absfuyu/game/game_stat.py +2 -2
- absfuyu/game/schulte.py +78 -0
- absfuyu/game/sudoku.py +2 -2
- absfuyu/game/tictactoe.py +2 -3
- absfuyu/game/wordle.py +6 -4
- absfuyu/general/__init__.py +4 -4
- absfuyu/general/content.py +4 -4
- absfuyu/general/human.py +2 -2
- absfuyu/general/resrel.py +213 -0
- absfuyu/general/shape.py +3 -8
- absfuyu/general/tax.py +344 -0
- absfuyu/logger.py +806 -59
- absfuyu/numbers/__init__.py +13 -0
- absfuyu/numbers/number_to_word.py +321 -0
- absfuyu/numbers/shorten_number.py +303 -0
- absfuyu/numbers/time_duration.py +217 -0
- absfuyu/pkg_data/__init__.py +2 -2
- absfuyu/pkg_data/deprecated.py +2 -2
- absfuyu/pkg_data/logo.py +1462 -0
- absfuyu/sort.py +4 -4
- absfuyu/tools/__init__.py +28 -2
- absfuyu/tools/checksum.py +144 -9
- absfuyu/tools/converter.py +120 -34
- absfuyu/tools/generator.py +461 -0
- absfuyu/tools/inspector.py +752 -0
- absfuyu/tools/keygen.py +2 -2
- absfuyu/tools/obfuscator.py +47 -9
- absfuyu/tools/passwordlib.py +89 -25
- absfuyu/tools/shutdownizer.py +3 -8
- absfuyu/tools/sw.py +718 -0
- absfuyu/tools/web.py +10 -13
- absfuyu/typings.py +138 -0
- absfuyu/util/__init__.py +114 -6
- absfuyu/util/api.py +41 -18
- absfuyu/util/cli.py +119 -0
- absfuyu/util/gui.py +91 -0
- absfuyu/util/json_method.py +43 -14
- absfuyu/util/lunar.py +2 -2
- absfuyu/util/package.py +124 -0
- absfuyu/util/path.py +702 -82
- absfuyu/util/performance.py +122 -7
- absfuyu/util/shorten_number.py +244 -21
- absfuyu/util/text_table.py +481 -0
- absfuyu/util/zipped.py +8 -7
- absfuyu/version.py +79 -59
- {absfuyu-5.0.0.dist-info → absfuyu-6.1.2.dist-info}/METADATA +52 -11
- absfuyu-6.1.2.dist-info/RECORD +105 -0
- {absfuyu-5.0.0.dist-info → absfuyu-6.1.2.dist-info}/WHEEL +1 -1
- absfuyu/extra/data_analysis.py +0 -1078
- absfuyu/general/generator.py +0 -303
- absfuyu-5.0.0.dist-info/RECORD +0 -68
- {absfuyu-5.0.0.dist-info → absfuyu-6.1.2.dist-info}/entry_points.txt +0 -0
- {absfuyu-5.0.0.dist-info → absfuyu-6.1.2.dist-info}/licenses/LICENSE +0 -0
absfuyu/sort.py
CHANGED
|
@@ -3,8 +3,8 @@ Absfuyu: Sort
|
|
|
3
3
|
-------------
|
|
4
4
|
Sort Module
|
|
5
5
|
|
|
6
|
-
Version: 1.
|
|
7
|
-
Date updated:
|
|
6
|
+
Version: 6.1.1
|
|
7
|
+
Date updated: 30/12/2025 (dd/mm/yyyy)
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
# Module level
|
|
@@ -26,7 +26,7 @@ from typing import Any
|
|
|
26
26
|
|
|
27
27
|
# Functions
|
|
28
28
|
# ---------------------------------------------------------------------------
|
|
29
|
-
def selection_sort(iterable: list, reverse: bool = False) -> list:
|
|
29
|
+
def selection_sort[T](iterable: list[T], reverse: bool = False) -> list[T]:
|
|
30
30
|
"""
|
|
31
31
|
Sort the list with selection sort (bubble sort) algorithm
|
|
32
32
|
|
|
@@ -61,7 +61,7 @@ def selection_sort(iterable: list, reverse: bool = False) -> list:
|
|
|
61
61
|
return iterable
|
|
62
62
|
|
|
63
63
|
|
|
64
|
-
def insertion_sort(iterable: list) -> list:
|
|
64
|
+
def insertion_sort[T](iterable: list[T]) -> list[T]:
|
|
65
65
|
"""
|
|
66
66
|
Sort the list with insertion sort algorithm
|
|
67
67
|
|
absfuyu/tools/__init__.py
CHANGED
|
@@ -3,6 +3,32 @@ Absfuyu: Tools
|
|
|
3
3
|
--------------
|
|
4
4
|
Some useful tools
|
|
5
5
|
|
|
6
|
-
Version:
|
|
7
|
-
Date updated:
|
|
6
|
+
Version: 6.1.1
|
|
7
|
+
Date updated: 30/12/2025 (dd/mm/yyyy)
|
|
8
8
|
"""
|
|
9
|
+
|
|
10
|
+
# Module Package
|
|
11
|
+
# ---------------------------------------------------------------------------
|
|
12
|
+
__all__ = [
|
|
13
|
+
# # Main
|
|
14
|
+
"Checksum",
|
|
15
|
+
"B64",
|
|
16
|
+
"T2C",
|
|
17
|
+
# "Charset",
|
|
18
|
+
# "Generator",
|
|
19
|
+
"Inspector",
|
|
20
|
+
"inspect_all",
|
|
21
|
+
# "Obfuscator",
|
|
22
|
+
# "StrShifter",
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# Library
|
|
27
|
+
# ---------------------------------------------------------------------------
|
|
28
|
+
from absfuyu.tools.checksum import Checksum
|
|
29
|
+
from absfuyu.tools.converter import Base64EncodeDecode as B64
|
|
30
|
+
from absfuyu.tools.converter import Text2Chemistry as T2C
|
|
31
|
+
from absfuyu.tools.inspector import Inspector, inspect_all
|
|
32
|
+
|
|
33
|
+
# from absfuyu.tools.generator import Charset, Generator # circular import bug
|
|
34
|
+
# from absfuyu.tools.obfuscator import Obfuscator, StrShifter # circular import bug
|
absfuyu/tools/checksum.py
CHANGED
|
@@ -3,13 +3,19 @@ Absufyu: Checksum
|
|
|
3
3
|
-----------------
|
|
4
4
|
Check MD5, SHA256, ...
|
|
5
5
|
|
|
6
|
-
Version:
|
|
7
|
-
Date updated:
|
|
6
|
+
Version: 6.1.1
|
|
7
|
+
Date updated: 30/12/2025 (dd/mm/yyyy)
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
# Module level
|
|
11
11
|
# ---------------------------------------------------------------------------
|
|
12
|
-
__all__ = [
|
|
12
|
+
__all__ = [
|
|
13
|
+
# Checksum
|
|
14
|
+
"Checksum",
|
|
15
|
+
"ChecksumMode",
|
|
16
|
+
# Mixin
|
|
17
|
+
"DirectoryRemoveDuplicateMixin",
|
|
18
|
+
]
|
|
13
19
|
|
|
14
20
|
|
|
15
21
|
# Library
|
|
@@ -19,7 +25,11 @@ from enum import StrEnum
|
|
|
19
25
|
from pathlib import Path
|
|
20
26
|
from typing import Literal
|
|
21
27
|
|
|
22
|
-
from absfuyu.core import BaseClass
|
|
28
|
+
from absfuyu.core.baseclass import BaseClass
|
|
29
|
+
from absfuyu.core.docstring import deprecated, versionadded, versionchanged
|
|
30
|
+
from absfuyu.core.dummy_func import tqdm
|
|
31
|
+
from absfuyu.dxt import DictExt, ListExt
|
|
32
|
+
from absfuyu.util.path import DirectoryBase
|
|
23
33
|
|
|
24
34
|
|
|
25
35
|
# Function
|
|
@@ -62,9 +72,70 @@ class ChecksumMode(StrEnum):
|
|
|
62
72
|
SHA512 = "sha512"
|
|
63
73
|
|
|
64
74
|
|
|
75
|
+
class DuplicateSummary(DictExt[str, list[Path]]):
|
|
76
|
+
"""
|
|
77
|
+
Duplicate file summary
|
|
78
|
+
"""
|
|
79
|
+
|
|
80
|
+
def summary(self) -> int:
|
|
81
|
+
"""
|
|
82
|
+
Show how many duplicates (include the original)
|
|
83
|
+
|
|
84
|
+
Returns
|
|
85
|
+
-------
|
|
86
|
+
int
|
|
87
|
+
How many duplicates
|
|
88
|
+
"""
|
|
89
|
+
temp = self.__class__(self.copy())
|
|
90
|
+
try:
|
|
91
|
+
return sum(temp.apply(lambda x: len(x)).values())
|
|
92
|
+
except Exception as err:
|
|
93
|
+
print(f"Something wrong - {err}")
|
|
94
|
+
|
|
95
|
+
def remove_duplicates(self, dry_run: bool = True, keep_first: bool = True, debug: bool = False) -> None:
|
|
96
|
+
"""
|
|
97
|
+
Remove duplicates
|
|
98
|
+
|
|
99
|
+
Parameters
|
|
100
|
+
----------
|
|
101
|
+
dry_run : bool, optional
|
|
102
|
+
Simulate only (no files deleted), by default ``True``
|
|
103
|
+
|
|
104
|
+
keep_first : bool, optional
|
|
105
|
+
Keep the first duplicate file, will keep the last duplicate file when ``False``, by default ``True``
|
|
106
|
+
"""
|
|
107
|
+
temp = self.__class__(self.copy())
|
|
108
|
+
removable_files = ListExt([x[1:] if keep_first else x[:-1] for x in temp.values()]).flatten()
|
|
109
|
+
|
|
110
|
+
for x in removable_files:
|
|
111
|
+
x: Path = x
|
|
112
|
+
|
|
113
|
+
if debug or dry_run:
|
|
114
|
+
print(f"Deleting {x}")
|
|
115
|
+
if dry_run:
|
|
116
|
+
continue
|
|
117
|
+
|
|
118
|
+
x.unlink(missing_ok=True)
|
|
119
|
+
|
|
120
|
+
|
|
65
121
|
@versionchanged("4.1.1", reason="Checksum for entire folder is possible")
|
|
66
122
|
@versionadded("4.1.0")
|
|
67
123
|
class Checksum(BaseClass):
|
|
124
|
+
"""
|
|
125
|
+
Checksum engine
|
|
126
|
+
|
|
127
|
+
Parameters
|
|
128
|
+
----------
|
|
129
|
+
path : str | Path
|
|
130
|
+
Path to file/directory to perform checksum
|
|
131
|
+
|
|
132
|
+
hash_mode : ChecksumMode | Literal["md5", "sha1", "sha256", "sha512"], optional
|
|
133
|
+
Hash mode, by default ``"sha256"``
|
|
134
|
+
|
|
135
|
+
save_result_to_file : bool, optional
|
|
136
|
+
Save checksum result(s) to file, by default ``False``
|
|
137
|
+
"""
|
|
138
|
+
|
|
68
139
|
def __init__(
|
|
69
140
|
self,
|
|
70
141
|
path: str | Path,
|
|
@@ -73,7 +144,8 @@ class Checksum(BaseClass):
|
|
|
73
144
|
) = ChecksumMode.SHA256,
|
|
74
145
|
save_result_to_file: bool = False,
|
|
75
146
|
) -> None:
|
|
76
|
-
"""
|
|
147
|
+
"""
|
|
148
|
+
Checksum engine
|
|
77
149
|
|
|
78
150
|
Parameters
|
|
79
151
|
----------
|
|
@@ -84,7 +156,7 @@ class Checksum(BaseClass):
|
|
|
84
156
|
Hash mode, by default ``"sha256"``
|
|
85
157
|
|
|
86
158
|
save_result_to_file : bool, optional
|
|
87
|
-
Save checksum result(s) to file, by default False
|
|
159
|
+
Save checksum result(s) to file, by default ``False``
|
|
88
160
|
"""
|
|
89
161
|
self.path = Path(path)
|
|
90
162
|
self.hash_mode = hash_mode
|
|
@@ -112,7 +184,8 @@ class Checksum(BaseClass):
|
|
|
112
184
|
"""This performs checksum"""
|
|
113
185
|
|
|
114
186
|
hash_engine = self._get_hash_engine().copy()
|
|
115
|
-
with open(Path(file), "rb") as f:
|
|
187
|
+
# with open(Path(file), "rb") as f:
|
|
188
|
+
with file.open("rb") as f:
|
|
116
189
|
# Read and hash the file in 4K chunks. Reading the whole
|
|
117
190
|
# file at once might consume a lot of memory if it is
|
|
118
191
|
# large.
|
|
@@ -125,12 +198,14 @@ class Checksum(BaseClass):
|
|
|
125
198
|
return hash_engine.hexdigest() # type: ignore
|
|
126
199
|
|
|
127
200
|
def checksum(self, recursive: bool = True) -> str:
|
|
128
|
-
"""
|
|
201
|
+
"""
|
|
202
|
+
Perform checksum
|
|
129
203
|
|
|
130
204
|
Parameters
|
|
131
205
|
----------
|
|
132
206
|
recursive : bool, optional
|
|
133
|
-
Do checksum for every file in the folder (including child folder),
|
|
207
|
+
Do checksum for every file in the folder (including child folder),
|
|
208
|
+
by default ``True``
|
|
134
209
|
|
|
135
210
|
Returns
|
|
136
211
|
-------
|
|
@@ -163,3 +238,63 @@ class Checksum(BaseClass):
|
|
|
163
238
|
f.write(output)
|
|
164
239
|
|
|
165
240
|
return output
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
# Mixin
|
|
244
|
+
class DirectoryRemoveDuplicateMixin(DirectoryBase):
|
|
245
|
+
"""
|
|
246
|
+
Directory - Remove duplicate by SHA256
|
|
247
|
+
|
|
248
|
+
- remove_duplicate
|
|
249
|
+
"""
|
|
250
|
+
|
|
251
|
+
def __init__(self, source_path, create_if_not_exist=False) -> None:
|
|
252
|
+
super().__init__(source_path, create_if_not_exist)
|
|
253
|
+
|
|
254
|
+
self._duplicate_cache: DuplicateSummary | None = None
|
|
255
|
+
|
|
256
|
+
def _gather_duplicate_cache(self, recursive: bool = True) -> None:
|
|
257
|
+
engine = Checksum(self.source_path, hash_mode=ChecksumMode.SHA256, save_result_to_file=False)
|
|
258
|
+
valid = [x for x in engine.path.glob("**/*" if recursive else "*") if x.is_file()]
|
|
259
|
+
checksum_cache = {}
|
|
260
|
+
|
|
261
|
+
# Checksum
|
|
262
|
+
for x in tqdm(valid, unit_scale=True, desc="Checking..."):
|
|
263
|
+
try:
|
|
264
|
+
cs_res = engine._checksum_operation(x)
|
|
265
|
+
|
|
266
|
+
if checksum_cache.get(cs_res) is None:
|
|
267
|
+
checksum_cache[cs_res] = [x]
|
|
268
|
+
else:
|
|
269
|
+
checksum_cache[cs_res] += [x]
|
|
270
|
+
except Exception as err:
|
|
271
|
+
print(f"ERROR: {x} - {err}")
|
|
272
|
+
continue
|
|
273
|
+
|
|
274
|
+
# Save to cache
|
|
275
|
+
self._duplicate_cache = DuplicateSummary({k: v for k, v in checksum_cache.items() if len(v) > 1})
|
|
276
|
+
|
|
277
|
+
def remove_duplicate(self, dry_run: bool = True, recursive: bool = True, debug: bool = True) -> None:
|
|
278
|
+
"""
|
|
279
|
+
Remove duplicate files by SHA256 checksum
|
|
280
|
+
|
|
281
|
+
Parameters
|
|
282
|
+
----------
|
|
283
|
+
dry_run : bool, optional
|
|
284
|
+
Simulate only (no files deleted), by default ``True``
|
|
285
|
+
|
|
286
|
+
recursive : bool, optional
|
|
287
|
+
Scan every file in the folder (including child folder), by default ``True``
|
|
288
|
+
|
|
289
|
+
debug : bool, optional
|
|
290
|
+
Print delete messages, by default ``True``
|
|
291
|
+
"""
|
|
292
|
+
self._gather_duplicate_cache(recursive=recursive)
|
|
293
|
+
|
|
294
|
+
# Remove
|
|
295
|
+
try:
|
|
296
|
+
summary = self._duplicate_cache
|
|
297
|
+
print(f"Duplicate files: {summary.summary()}")
|
|
298
|
+
summary.remove_duplicates(dry_run=dry_run, keep_first=False, debug=debug)
|
|
299
|
+
except Exception as err:
|
|
300
|
+
pass
|
absfuyu/tools/converter.py
CHANGED
|
@@ -3,8 +3,8 @@ Absufyu: Converter
|
|
|
3
3
|
------------------
|
|
4
4
|
Convert stuff
|
|
5
5
|
|
|
6
|
-
Version:
|
|
7
|
-
Date updated:
|
|
6
|
+
Version: 6.1.1
|
|
7
|
+
Date updated: 30/12/2025 (dd/mm/yyyy)
|
|
8
8
|
|
|
9
9
|
Feature:
|
|
10
10
|
--------
|
|
@@ -16,9 +16,11 @@ Feature:
|
|
|
16
16
|
# Module level
|
|
17
17
|
# ---------------------------------------------------------------------------
|
|
18
18
|
__all__ = [
|
|
19
|
+
"Base64EncodeDecode",
|
|
19
20
|
"Text2Chemistry",
|
|
20
21
|
"Str2Pixel",
|
|
21
|
-
|
|
22
|
+
# Support
|
|
23
|
+
"ChemistryElement",
|
|
22
24
|
]
|
|
23
25
|
|
|
24
26
|
|
|
@@ -32,10 +34,11 @@ from itertools import chain, combinations
|
|
|
32
34
|
from pathlib import Path
|
|
33
35
|
from typing import Self
|
|
34
36
|
|
|
35
|
-
from absfuyu.core import BaseClass, CLITextColor
|
|
37
|
+
from absfuyu.core.baseclass import BaseClass, CLITextColor
|
|
38
|
+
from absfuyu.core.docstring import versionadded
|
|
36
39
|
from absfuyu.logger import logger
|
|
37
40
|
from absfuyu.pkg_data import DataList, DataLoader
|
|
38
|
-
from absfuyu.util import
|
|
41
|
+
from absfuyu.util.text_table import OneColumnTableMaker
|
|
39
42
|
|
|
40
43
|
|
|
41
44
|
# Class
|
|
@@ -84,14 +87,43 @@ class Base64EncodeDecode(BaseClass):
|
|
|
84
87
|
|
|
85
88
|
|
|
86
89
|
class ChemistryElement(BaseClass):
|
|
87
|
-
"""
|
|
90
|
+
"""
|
|
91
|
+
Chemistry Element
|
|
92
|
+
|
|
93
|
+
Parameters
|
|
94
|
+
----------
|
|
95
|
+
name : str
|
|
96
|
+
Element name
|
|
97
|
+
|
|
98
|
+
number : int
|
|
99
|
+
Order in periodic table
|
|
100
|
+
|
|
101
|
+
symbol : str
|
|
102
|
+
Short symbol of element
|
|
103
|
+
|
|
104
|
+
atomic_mass : float
|
|
105
|
+
Atomic mass of element
|
|
106
|
+
"""
|
|
107
|
+
|
|
108
|
+
__slots__ = ("name", "number", "symbol", "atomic_mass")
|
|
88
109
|
|
|
89
110
|
def __init__(self, name: str, number: int, symbol: str, atomic_mass: float) -> None:
|
|
90
111
|
"""
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
112
|
+
Chemistry Element
|
|
113
|
+
|
|
114
|
+
Parameters
|
|
115
|
+
----------
|
|
116
|
+
name : str
|
|
117
|
+
Element name
|
|
118
|
+
|
|
119
|
+
number : int
|
|
120
|
+
Order in periodic table
|
|
121
|
+
|
|
122
|
+
symbol : str
|
|
123
|
+
Short symbol of element
|
|
124
|
+
|
|
125
|
+
atomic_mass : float
|
|
126
|
+
Atomic mass of element
|
|
95
127
|
"""
|
|
96
128
|
self.name = name
|
|
97
129
|
self.number = number
|
|
@@ -105,23 +137,28 @@ class ChemistryElement(BaseClass):
|
|
|
105
137
|
"""
|
|
106
138
|
Output content to dict
|
|
107
139
|
|
|
108
|
-
|
|
140
|
+
Returns
|
|
141
|
+
-------
|
|
142
|
+
dict[str, str | int | float]
|
|
143
|
+
Dict version of element
|
|
109
144
|
"""
|
|
110
|
-
return {
|
|
111
|
-
|
|
112
|
-
"number": self.number,
|
|
113
|
-
"symbol": self.symbol,
|
|
114
|
-
"atomic_mass": self.atomic_mass,
|
|
115
|
-
}
|
|
145
|
+
# return {"name": self.name, "number": self.number, "symbol": self.symbol, "atomic_mass": self.atomic_mass}
|
|
146
|
+
return {x: getattr(self, x) for x in self.__slots__}
|
|
116
147
|
|
|
117
148
|
@classmethod
|
|
118
149
|
def from_dict(cls, data: dict[str, str | int | float]) -> Self:
|
|
119
150
|
"""
|
|
120
151
|
Convert from ``dict`` data
|
|
121
152
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
:
|
|
153
|
+
Parameters
|
|
154
|
+
----------
|
|
155
|
+
data : dict[str, str | int | float]
|
|
156
|
+
Dict data
|
|
157
|
+
|
|
158
|
+
Returns
|
|
159
|
+
-------
|
|
160
|
+
Self
|
|
161
|
+
ChemistryElement
|
|
125
162
|
"""
|
|
126
163
|
return cls(
|
|
127
164
|
name=data["name"], # type: ignore
|
|
@@ -132,6 +169,10 @@ class ChemistryElement(BaseClass):
|
|
|
132
169
|
|
|
133
170
|
|
|
134
171
|
class Text2Chemistry(BaseClass):
|
|
172
|
+
"""
|
|
173
|
+
Convert text into chemistry symbols.
|
|
174
|
+
"""
|
|
175
|
+
|
|
135
176
|
def __init__(self) -> None:
|
|
136
177
|
self.data_location = DataList.CHEMISTRY
|
|
137
178
|
|
|
@@ -150,7 +191,10 @@ class Text2Chemistry(BaseClass):
|
|
|
150
191
|
"""
|
|
151
192
|
Characters that can not be converted (unvailable chemistry symbol)
|
|
152
193
|
|
|
153
|
-
|
|
194
|
+
Returns
|
|
195
|
+
-------
|
|
196
|
+
set[str]
|
|
197
|
+
Set of unvailable characters
|
|
154
198
|
"""
|
|
155
199
|
base = set(string.ascii_lowercase)
|
|
156
200
|
available = set(
|
|
@@ -164,10 +208,20 @@ class Text2Chemistry(BaseClass):
|
|
|
164
208
|
"""
|
|
165
209
|
Convert text to chemistry symbol
|
|
166
210
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
211
|
+
Parameters
|
|
212
|
+
----------
|
|
213
|
+
text : str
|
|
214
|
+
Desired text
|
|
215
|
+
|
|
216
|
+
Returns
|
|
217
|
+
-------
|
|
218
|
+
list[list[ChemistryElement]] | list
|
|
219
|
+
Converted text (empty list when failed to convert)
|
|
220
|
+
|
|
221
|
+
Raises
|
|
222
|
+
------
|
|
223
|
+
ValueError
|
|
224
|
+
When text contains digit, whitespaces, ...
|
|
171
225
|
"""
|
|
172
226
|
# Check if `text` is a word (without digits)
|
|
173
227
|
is_word_pattern = r"^[a-zA-Z]+$"
|
|
@@ -253,21 +307,50 @@ class Text2Chemistry(BaseClass):
|
|
|
253
307
|
if len(result) == 0:
|
|
254
308
|
res = "No possible combination"
|
|
255
309
|
else:
|
|
256
|
-
|
|
310
|
+
header = ["Text to Chemistry"]
|
|
311
|
+
body = []
|
|
312
|
+
max_table_len = len(header[0])
|
|
313
|
+
|
|
257
314
|
for i, solution in enumerate(result, start=1):
|
|
315
|
+
msg = []
|
|
258
316
|
max_word_len = max([len(x.name) for x in solution])
|
|
259
317
|
msg.append(f"Option {i:02}: {', '.join([x.symbol for x in solution])}")
|
|
260
318
|
for x in solution:
|
|
261
319
|
msg.append(
|
|
262
|
-
f"{x.symbol.ljust(2)}
|
|
320
|
+
f"{x.symbol.ljust(2)} "
|
|
321
|
+
f"({x.number:02}. {x.name.ljust(max_word_len)}"
|
|
322
|
+
f" - {round(x.atomic_mass, 2)})"
|
|
263
323
|
)
|
|
264
|
-
|
|
265
|
-
|
|
324
|
+
body.append(msg)
|
|
325
|
+
|
|
326
|
+
max_table_len = max(
|
|
327
|
+
max([max([len(x) for x in opt]) for opt in body]), max_table_len
|
|
328
|
+
)
|
|
329
|
+
table = OneColumnTableMaker(ncols=max_table_len + 4, style="normal")
|
|
330
|
+
table.add_paragraph(header)
|
|
331
|
+
for x in body:
|
|
332
|
+
table.add_paragraph(x)
|
|
333
|
+
|
|
334
|
+
res = table.make_table()
|
|
266
335
|
return res
|
|
267
336
|
|
|
268
337
|
|
|
269
338
|
class Str2Pixel(BaseClass):
|
|
270
|
-
"""
|
|
339
|
+
"""
|
|
340
|
+
Convert str into pixel
|
|
341
|
+
|
|
342
|
+
Parameters
|
|
343
|
+
----------
|
|
344
|
+
str_data : str
|
|
345
|
+
| Pixel string data (Format: ``<number_of_pixel><color_code>``)
|
|
346
|
+
| Example: ``50w20b`` = 50 white pixels and 20 black pixels
|
|
347
|
+
|
|
348
|
+
pixel_size : int, optional
|
|
349
|
+
Pixel size, by default ``2``
|
|
350
|
+
|
|
351
|
+
pixel_symbol_overwrite : str | None, optional
|
|
352
|
+
Overwrite pixel symbol, by default ``None``
|
|
353
|
+
"""
|
|
271
354
|
|
|
272
355
|
PIXEL = "\u2588"
|
|
273
356
|
|
|
@@ -279,11 +362,13 @@ class Str2Pixel(BaseClass):
|
|
|
279
362
|
pixel_symbol_overwrite: str | None = None,
|
|
280
363
|
) -> None:
|
|
281
364
|
"""
|
|
365
|
+
Convert str into pixel
|
|
366
|
+
|
|
282
367
|
Parameters
|
|
283
368
|
----------
|
|
284
369
|
str_data : str
|
|
285
|
-
Pixel string data (Format: ``<number_of_pixel><color_code>``)
|
|
286
|
-
Example: 50w20b = 50 white pixels and 20 black pixels
|
|
370
|
+
| Pixel string data (Format: ``<number_of_pixel><color_code>``)
|
|
371
|
+
| Example: ``50w20b`` = 50 white pixels and 20 black pixels
|
|
287
372
|
|
|
288
373
|
pixel_size : int, optional
|
|
289
374
|
Pixel size, by default ``2``
|
|
@@ -293,7 +378,7 @@ class Str2Pixel(BaseClass):
|
|
|
293
378
|
"""
|
|
294
379
|
self.data = str_data
|
|
295
380
|
if pixel_symbol_overwrite is None:
|
|
296
|
-
self.pixel = self.PIXEL * int(
|
|
381
|
+
self.pixel = self.PIXEL * int(max(pixel_size, 1))
|
|
297
382
|
else:
|
|
298
383
|
self.pixel = pixel_symbol_overwrite
|
|
299
384
|
|
|
@@ -307,7 +392,8 @@ class Str2Pixel(BaseClass):
|
|
|
307
392
|
return [x for y in zip(num, char) for x in y]
|
|
308
393
|
|
|
309
394
|
def convert(self, line_break: bool = True) -> str:
|
|
310
|
-
"""
|
|
395
|
+
"""
|
|
396
|
+
Convert data into pixel
|
|
311
397
|
|
|
312
398
|
Parameters
|
|
313
399
|
----------
|