absfuyu 4.0.0__tar.gz → 4.1.0__tar.gz
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-4.0.0 → absfuyu-4.1.0}/LICENSE +21 -21
- {absfuyu-4.0.0 → absfuyu-4.1.0}/PKG-INFO +2 -1
- {absfuyu-4.0.0 → absfuyu-4.1.0}/pyproject.toml +42 -12
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/__init__.py +1 -1
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/cli/do_group.py +39 -2
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/core.py +15 -2
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/game/__init__.py +1 -1
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/game/game_stat.py +1 -1
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/general/content.py +7 -7
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/general/data_extension.py +3 -3
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/general/generator.py +4 -2
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/logger.py +2 -2
- absfuyu-4.1.0/src/absfuyu/tools/checksum.py +56 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/tools/converter.py +26 -2
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/tools/obfuscator.py +1 -1
- absfuyu-4.1.0/src/absfuyu/util/shorten_number.py +228 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/tests/test_everything.py +7 -2
- {absfuyu-4.0.0 → absfuyu-4.1.0}/tests/test_tarot.py +3 -3
- {absfuyu-4.0.0 → absfuyu-4.1.0}/tests/test_util.py +34 -6
- {absfuyu-4.0.0 → absfuyu-4.1.0}/tests/test_version.py +13 -14
- {absfuyu-4.0.0 → absfuyu-4.1.0}/.gitignore +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/README.md +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/dev_requirements.txt +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/docs/Makefile +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/docs/conf.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/docs/index.rst +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/docs/info.md +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/docs/make.bat +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/docs/modules.rst +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/images/repository-image-crop.png +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/images/repository-image-white.png +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/images/repository-image.png +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/__main__.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/cli/__init__.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/cli/color.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/cli/config_group.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/cli/game_group.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/config/__init__.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/config/config.json +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/everything.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/extensions/__init__.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/extensions/beautiful.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/extensions/dev/__init__.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/extensions/dev/password_hash.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/extensions/dev/passwordlib.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/extensions/dev/project_starter.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/extensions/dev/shutdownizer.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/extensions/extra/__init__.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/extensions/extra/data_analysis.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/fun/WGS.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/fun/__init__.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/fun/tarot.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/game/sudoku.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/game/tictactoe.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/game/wordle.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/general/__init__.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/general/human.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/pkg_data/__init__.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/pkg_data/chemistry.pkl +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/pkg_data/tarot.pkl +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/py.typed +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/sort.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/tools/__init__.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/tools/keygen.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/tools/stats.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/tools/web.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/util/__init__.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/util/api.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/util/json_method.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/util/lunar.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/util/path.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/util/performance.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/util/pkl.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/util/zipped.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/src/absfuyu/version.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/tests/__init__.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/tests/conftest.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/tests/test_beautiful.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/tests/test_config.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/tests/test_data_analysis.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/tests/test_data_extension.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/tests/test_extensions.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/tests/test_fun.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/tests/test_game.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/tests/test_generator.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/tests/test_logger.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/tests/test_passwordlib.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/tests/test_pkg_data.py +0 -0
- {absfuyu-4.0.0 → absfuyu-4.1.0}/tests/test_tools.py +0 -0
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2022-
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022-2025 AbsoluteWinter
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: absfuyu
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.1.0
|
|
4
4
|
Summary: A small collection of code
|
|
5
5
|
Project-URL: Homepage, https://github.com/AbsoluteWinter/absfuyu-public
|
|
6
6
|
Project-URL: Documentation, https://absolutewinter.github.io/absfuyu-docs/
|
|
@@ -46,6 +46,7 @@ Requires-Dist: absfuyu-res; extra == 'full'
|
|
|
46
46
|
Requires-Dist: numpy; extra == 'full'
|
|
47
47
|
Requires-Dist: pandas; extra == 'full'
|
|
48
48
|
Requires-Dist: rich; extra == 'full'
|
|
49
|
+
Requires-Dist: tqdm; extra == 'full'
|
|
49
50
|
Provides-Extra: res
|
|
50
51
|
Requires-Dist: absfuyu-res; extra == 'res'
|
|
51
52
|
Description-Content-Type: text/markdown
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
# 4. Build package (hatch build)
|
|
6
6
|
# 5. Generating docs (hatch run docs:build)
|
|
7
7
|
# 6. Publish packge (hatch publish)
|
|
8
|
-
## Run entire workflow: hatch run workflow
|
|
8
|
+
## Run entire workflow: hatch run workflow:<major | minor | patch>
|
|
9
9
|
## `hatch env show` for more information
|
|
10
10
|
|
|
11
11
|
# MARK: BUILD ====================
|
|
@@ -60,7 +60,7 @@ Issues = "https://github.com/AbsoluteWinter/absfuyu-public/issues"
|
|
|
60
60
|
|
|
61
61
|
[project.optional-dependencies]
|
|
62
62
|
res = ["absfuyu-res"]
|
|
63
|
-
full = ["absfuyu-res", "numpy", "pandas", "rich"]
|
|
63
|
+
full = ["absfuyu-res", "numpy", "pandas", "rich", "tqdm"]
|
|
64
64
|
beautiful = ["rich"]
|
|
65
65
|
extra = ["numpy", "pandas"]
|
|
66
66
|
dev = ["hatch", "pytest"]
|
|
@@ -171,12 +171,12 @@ detached = true
|
|
|
171
171
|
skip-install = true
|
|
172
172
|
description = """
|
|
173
173
|
Package workflow:
|
|
174
|
-
hatch run workflow
|
|
174
|
+
hatch run workflow:<option>
|
|
175
175
|
|
|
176
|
-
|
|
177
|
-
-
|
|
178
|
-
-
|
|
179
|
-
-
|
|
176
|
+
Options:
|
|
177
|
+
- patch: release version patch
|
|
178
|
+
- minor: release version minor
|
|
179
|
+
- major: release version major
|
|
180
180
|
"""
|
|
181
181
|
|
|
182
182
|
[tool.hatch.envs.workflow.scripts]
|
|
@@ -186,25 +186,54 @@ test = [
|
|
|
186
186
|
"hatch run all:test", # Test
|
|
187
187
|
]
|
|
188
188
|
build = [
|
|
189
|
+
# Update license year - Convert to hex due to unable to run multiple lines
|
|
190
|
+
# Source code:
|
|
191
|
+
# import re;from datetime import datetime;from pathlib import Path
|
|
192
|
+
# print("Updating license year...");p=r"([12]\d{3})(-[12]\d{3})?"
|
|
193
|
+
# n=str(datetime.now().year);l=list(Path.cwd().glob("*license*"))[0]
|
|
194
|
+
# with open(l)as f:c=f.readlines()
|
|
195
|
+
# for i,x in enumerate(c):
|
|
196
|
+
# s=re.search(p,x);y=s.groups()[0]if s else n
|
|
197
|
+
# if y!=n:c[i]=re.sub(p,f"{y}-{n}",x)
|
|
198
|
+
# with open(l,"w",encoding="utf-8")as f:f.writelines(c)
|
|
199
|
+
# print("License year updated")
|
|
200
|
+
"""
|
|
201
|
+
python -c \"exec(bytes.fromhex('696d706f72742072653b66726f6d20646174657\
|
|
202
|
+
4696d6520696d706f7274206461746574696d653b66726f6d20706174686c696220696d\
|
|
203
|
+
706f727420506174680a7072696e7428225570646174696e67206c6963656e736520796\
|
|
204
|
+
561722e2e2e22293b703d7222285b31325d5c647b337d29282d5b31325d5c647b337d29\
|
|
205
|
+
3f220a6e3d737472286461746574696d652e6e6f7728292e79656172293b6c3d6c69737\
|
|
206
|
+
428506174682e63776428292e676c6f6228222a6c6963656e73652a2229295b305d0a77\
|
|
207
|
+
697468206f70656e286c29617320663a633d662e726561646c696e657328290a666f722\
|
|
208
|
+
0692c7820696e20656e756d65726174652863293a0a20202020733d72652e7365617263\
|
|
209
|
+
6828702c78293b793d732e67726f75707328295b305d6966207320656c7365206e0a202\
|
|
210
|
+
0202069662079213d6e3a635b695d3d72652e73756228702c66227b797d2d7b6e7d222c\
|
|
211
|
+
78290a77697468206f70656e286c2c2277222c656e636f64696e673d227574662d38222\
|
|
212
|
+
9617320663a662e77726974656c696e65732863290a7072696e7428224c6963656e7365\
|
|
213
|
+
207965617220757064617465642229').decode('utf-8'))\"
|
|
214
|
+
""",
|
|
215
|
+
# "python support_scripts/update_license_year.py", # Update license year
|
|
189
216
|
"hatch clean", # Clean dist/ folder
|
|
190
217
|
"hatch -v build", # Build package
|
|
191
218
|
"hatch run docs:build", # Build docs
|
|
192
|
-
"hatch publish", # Publish
|
|
193
219
|
]
|
|
194
|
-
|
|
220
|
+
patch = [
|
|
195
221
|
"test",
|
|
196
222
|
"hatch version patch", # Bump version patch
|
|
197
223
|
"build",
|
|
224
|
+
"hatch publish", # Publish
|
|
198
225
|
]
|
|
199
|
-
|
|
226
|
+
minor = [
|
|
200
227
|
"test",
|
|
201
228
|
"hatch version minor", # Bump version minor
|
|
202
229
|
"build",
|
|
230
|
+
"hatch publish", # Publish
|
|
203
231
|
]
|
|
204
|
-
|
|
232
|
+
major = [
|
|
205
233
|
"test",
|
|
206
234
|
"hatch version major", # Bump version major
|
|
207
235
|
"build",
|
|
236
|
+
"hatch publish", # Publish
|
|
208
237
|
]
|
|
209
238
|
|
|
210
239
|
# MARK: TOOL: pytest
|
|
@@ -223,7 +252,7 @@ markers = [ # pytest -m <marker> -v
|
|
|
223
252
|
|
|
224
253
|
# MARK: TOOL: mypy
|
|
225
254
|
[tool.mypy]
|
|
226
|
-
|
|
255
|
+
python_version = "3.11"
|
|
227
256
|
mypy_path = "src"
|
|
228
257
|
check_untyped_defs = true
|
|
229
258
|
# disallow_any_generics = true
|
|
@@ -279,6 +308,7 @@ ignore = [
|
|
|
279
308
|
"tests/*" = [
|
|
280
309
|
"F401", # imported but unused
|
|
281
310
|
]
|
|
311
|
+
"shorten_number.py" = ["B007"] # Loop control variable not used within loop body
|
|
282
312
|
|
|
283
313
|
# MARK: TOOL: black
|
|
284
314
|
[tool.black]
|
|
@@ -3,13 +3,14 @@ ABSFUYU CLI
|
|
|
3
3
|
-----------
|
|
4
4
|
Do
|
|
5
5
|
|
|
6
|
-
Version: 1.
|
|
7
|
-
Date updated:
|
|
6
|
+
Version: 1.3.0
|
|
7
|
+
Date updated: 01/02/2025 (dd/mm/yyyy)
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
__all__ = ["do_group"]
|
|
11
11
|
|
|
12
12
|
import subprocess
|
|
13
|
+
from typing import Literal
|
|
13
14
|
|
|
14
15
|
import click
|
|
15
16
|
|
|
@@ -17,6 +18,7 @@ from absfuyu import __title__
|
|
|
17
18
|
from absfuyu.cli.color import COLOR
|
|
18
19
|
from absfuyu.core import __package_feature__
|
|
19
20
|
from absfuyu.general.human import Human2
|
|
21
|
+
from absfuyu.tools.checksum import checksum_operation
|
|
20
22
|
from absfuyu.util.zipped import Zipper
|
|
21
23
|
from absfuyu.version import PkgVersion
|
|
22
24
|
|
|
@@ -96,6 +98,40 @@ def unzip_files_in_dir(dir: str) -> None:
|
|
|
96
98
|
print("Done")
|
|
97
99
|
|
|
98
100
|
|
|
101
|
+
@click.command(name="checksum")
|
|
102
|
+
@click.argument("file_path", type=str)
|
|
103
|
+
@click.option(
|
|
104
|
+
"--hashmode",
|
|
105
|
+
"-m",
|
|
106
|
+
"hash_mode",
|
|
107
|
+
type=click.Choice(["md5", "sha1", "sha256", "sha512"]),
|
|
108
|
+
default="sha256",
|
|
109
|
+
show_default=True,
|
|
110
|
+
help="Hash mode",
|
|
111
|
+
)
|
|
112
|
+
@click.option(
|
|
113
|
+
"--compare",
|
|
114
|
+
"-c",
|
|
115
|
+
"hash_to_compare",
|
|
116
|
+
type=str,
|
|
117
|
+
default=None,
|
|
118
|
+
show_default=True,
|
|
119
|
+
help="Hash to compare",
|
|
120
|
+
)
|
|
121
|
+
def file_checksum(
|
|
122
|
+
file_path: str,
|
|
123
|
+
hash_mode: str | Literal["md5", "sha1", "sha256", "sha512"],
|
|
124
|
+
hash_to_compare: str,
|
|
125
|
+
) -> None:
|
|
126
|
+
"""Checksum for file"""
|
|
127
|
+
|
|
128
|
+
res = checksum_operation(file_path, hash_mode=hash_mode)
|
|
129
|
+
if hash_to_compare:
|
|
130
|
+
print(res == hash_to_compare)
|
|
131
|
+
else:
|
|
132
|
+
print(res)
|
|
133
|
+
|
|
134
|
+
|
|
99
135
|
@click.group(name="do")
|
|
100
136
|
def do_group() -> None:
|
|
101
137
|
"""Perform functionalities"""
|
|
@@ -108,3 +144,4 @@ do_group.add_command(advice)
|
|
|
108
144
|
do_group.add_command(fs)
|
|
109
145
|
do_group.add_command(info)
|
|
110
146
|
do_group.add_command(unzip_files_in_dir)
|
|
147
|
+
do_group.add_command(file_checksum)
|
|
@@ -3,8 +3,8 @@ Absfuyu: Core
|
|
|
3
3
|
-------------
|
|
4
4
|
Contain type hints and other stuffs
|
|
5
5
|
|
|
6
|
-
Version: 2.
|
|
7
|
-
Date updated:
|
|
6
|
+
Version: 2.3.0
|
|
7
|
+
Date updated: 01/02/2025 (dd/mm/yyyy)
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
# Module Package
|
|
@@ -21,7 +21,11 @@ __all__ = [
|
|
|
21
21
|
__package_feature__ = ["beautiful", "extra", "res", "full", "dev"]
|
|
22
22
|
|
|
23
23
|
|
|
24
|
+
# Library
|
|
25
|
+
###########################################################################
|
|
26
|
+
from importlib import import_module
|
|
24
27
|
from importlib.resources import files
|
|
28
|
+
from typing import Iterable
|
|
25
29
|
|
|
26
30
|
|
|
27
31
|
class CLITextColor:
|
|
@@ -43,3 +47,12 @@ class CLITextColor:
|
|
|
43
47
|
CORE_PATH = files("absfuyu")
|
|
44
48
|
CONFIG_PATH = CORE_PATH.joinpath("config", "config.json")
|
|
45
49
|
DATA_PATH = CORE_PATH.joinpath("pkg_data")
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
# tqdm wrapper
|
|
53
|
+
try:
|
|
54
|
+
tqdm = import_module("tqdm").tqdm
|
|
55
|
+
except ModuleNotFoundError:
|
|
56
|
+
|
|
57
|
+
def tqdm(iterable: Iterable, **kwargs):
|
|
58
|
+
return iterable
|
|
@@ -26,7 +26,7 @@ class GameStats:
|
|
|
26
26
|
def _update_win_rate(self) -> None:
|
|
27
27
|
try:
|
|
28
28
|
self._win_rate = self.win / (self.win + self.draw + self.lose)
|
|
29
|
-
self.win_rate = f"{self._win_rate*100:,.2f}%"
|
|
29
|
+
self.win_rate = f"{self._win_rate * 100:,.2f}%"
|
|
30
30
|
except ZeroDivisionError:
|
|
31
31
|
self._win_rate = 0
|
|
32
32
|
self.win_rate = "N/A"
|
|
@@ -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)
|
|
@@ -302,7 +302,7 @@ class Text(str):
|
|
|
302
302
|
output.append(f"{splt_name[i]}='{temp[i]}'")
|
|
303
303
|
else:
|
|
304
304
|
for i in range(splt_len):
|
|
305
|
-
output.append(f"{custom_var_name}{i+1}='{temp[i]}'")
|
|
305
|
+
output.append(f"{custom_var_name}{i + 1}='{temp[i]}'")
|
|
306
306
|
|
|
307
307
|
# joined variable
|
|
308
308
|
temp = []
|
|
@@ -319,9 +319,9 @@ class Text(str):
|
|
|
319
319
|
if i == 0:
|
|
320
320
|
temp.append(f"{custom_var_name}=")
|
|
321
321
|
if i == splt_len - 1:
|
|
322
|
-
temp.append(f"{custom_var_name}{i+1}")
|
|
322
|
+
temp.append(f"{custom_var_name}{i + 1}")
|
|
323
323
|
else:
|
|
324
|
-
temp.append(f"{custom_var_name}{i+1}+")
|
|
324
|
+
temp.append(f"{custom_var_name}{i + 1}+")
|
|
325
325
|
|
|
326
326
|
output.append("".join(temp))
|
|
327
327
|
if custom_var_name is None:
|
|
@@ -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}")
|
|
@@ -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
|
|
|
@@ -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
|
|
@@ -3,8 +3,8 @@ Absufyu: Converter
|
|
|
3
3
|
------------------
|
|
4
4
|
Convert stuff
|
|
5
5
|
|
|
6
|
-
Version: 1.
|
|
7
|
-
Date updated:
|
|
6
|
+
Version: 1.3.0
|
|
7
|
+
Date updated: 01/02/2025 (dd/mm/yyyy)
|
|
8
8
|
|
|
9
9
|
Feature:
|
|
10
10
|
--------
|
|
@@ -25,6 +25,7 @@ import math
|
|
|
25
25
|
import re
|
|
26
26
|
import string
|
|
27
27
|
from itertools import chain, combinations
|
|
28
|
+
from pathlib import Path
|
|
28
29
|
|
|
29
30
|
from absfuyu.core import CLITextColor
|
|
30
31
|
from absfuyu.logger import logger
|
|
@@ -48,6 +49,29 @@ class Base64EncodeDecode:
|
|
|
48
49
|
def decode(data: str) -> str:
|
|
49
50
|
return base64.b64decode(data).decode()
|
|
50
51
|
|
|
52
|
+
@staticmethod
|
|
53
|
+
def encode_image(img_path: Path | str, data_tag: bool = False) -> str:
|
|
54
|
+
"""Encode image file into base64 string
|
|
55
|
+
|
|
56
|
+
Parameters
|
|
57
|
+
----------
|
|
58
|
+
img_path : Path | str
|
|
59
|
+
Path to image
|
|
60
|
+
data_tag : bool, optional
|
|
61
|
+
Add data tag before base64 string, by default False
|
|
62
|
+
|
|
63
|
+
Returns
|
|
64
|
+
-------
|
|
65
|
+
str
|
|
66
|
+
Encoded image
|
|
67
|
+
"""
|
|
68
|
+
img = Path(img_path)
|
|
69
|
+
with open(img, "rb") as img_file:
|
|
70
|
+
b64_data = base64.b64encode(img_file.read()).decode("utf-8")
|
|
71
|
+
if data_tag:
|
|
72
|
+
return f"data:image/{img.suffix[1:]};charset=utf-8;base64,{b64_data}"
|
|
73
|
+
return b64_data
|
|
74
|
+
|
|
51
75
|
|
|
52
76
|
class ChemistryElement:
|
|
53
77
|
"""Chemistry Element"""
|
|
@@ -217,7 +217,7 @@ class Obfuscator:
|
|
|
217
217
|
)
|
|
218
218
|
for x in bait_lst:
|
|
219
219
|
output.append(
|
|
220
|
-
f"{x}='{gen.generate_string(charset=Charset.DEFAULT,size=self.split_every_length,times=1,string_type_if_1=True)}'"
|
|
220
|
+
f"{x}='{gen.generate_string(charset=Charset.DEFAULT, size=self.split_every_length, times=1, string_type_if_1=True)}'"
|
|
221
221
|
)
|
|
222
222
|
|
|
223
223
|
random_eval_text = str(random.randint(1, 100))
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Absfuyu: Shorten number
|
|
3
|
+
---------------
|
|
4
|
+
Short number base on suffixes
|
|
5
|
+
|
|
6
|
+
Version: 1.0.0
|
|
7
|
+
Last update: 01/02/2025 (dd/mm/yyyy)
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
# Module level
|
|
11
|
+
###########################################################################
|
|
12
|
+
__all__ = ["UnitSuffixFactory", "CommonUnitSuffixesFactory", "Decimal"]
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# Library
|
|
16
|
+
###########################################################################
|
|
17
|
+
from dataclasses import dataclass, field
|
|
18
|
+
from typing import Annotated, NamedTuple, Self
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# Class
|
|
22
|
+
###########################################################################
|
|
23
|
+
class UnitSuffixFactory(NamedTuple):
|
|
24
|
+
base: int
|
|
25
|
+
short_name: list[str]
|
|
26
|
+
full_name: list[str]
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class CommonUnitSuffixesFactory:
|
|
30
|
+
NUMBER = UnitSuffixFactory(
|
|
31
|
+
1000,
|
|
32
|
+
[
|
|
33
|
+
"",
|
|
34
|
+
"K",
|
|
35
|
+
"M",
|
|
36
|
+
"B",
|
|
37
|
+
"T",
|
|
38
|
+
"Qa",
|
|
39
|
+
"Qi",
|
|
40
|
+
"Sx",
|
|
41
|
+
"Sp",
|
|
42
|
+
"Oc",
|
|
43
|
+
"No",
|
|
44
|
+
"Dc",
|
|
45
|
+
"Ud",
|
|
46
|
+
"Dd",
|
|
47
|
+
"Td",
|
|
48
|
+
"Qad",
|
|
49
|
+
"Qid",
|
|
50
|
+
"Sxd",
|
|
51
|
+
"Spd",
|
|
52
|
+
"Ocd",
|
|
53
|
+
"Nod",
|
|
54
|
+
"Vg",
|
|
55
|
+
"Uvg",
|
|
56
|
+
"Dvg",
|
|
57
|
+
"Tvg",
|
|
58
|
+
"Qavg",
|
|
59
|
+
"Qivg",
|
|
60
|
+
"Sxvg",
|
|
61
|
+
"Spvg",
|
|
62
|
+
"Ovg",
|
|
63
|
+
"Nvg",
|
|
64
|
+
"Tg",
|
|
65
|
+
"Utg",
|
|
66
|
+
"Dtg",
|
|
67
|
+
"Ttg",
|
|
68
|
+
"Qatg",
|
|
69
|
+
"Qitg",
|
|
70
|
+
"Sxtg",
|
|
71
|
+
"Sptg",
|
|
72
|
+
"Otg",
|
|
73
|
+
"Ntg",
|
|
74
|
+
],
|
|
75
|
+
[
|
|
76
|
+
"", # < Thousand
|
|
77
|
+
"Thousand",
|
|
78
|
+
"Million",
|
|
79
|
+
"Billion", # 1e9
|
|
80
|
+
"Trillion",
|
|
81
|
+
"Quadrillion",
|
|
82
|
+
"Quintillion",
|
|
83
|
+
"Sextillion",
|
|
84
|
+
"Septillion",
|
|
85
|
+
"Octillion",
|
|
86
|
+
"Nonillion",
|
|
87
|
+
"Decillion", # 1e33
|
|
88
|
+
"Undecillion",
|
|
89
|
+
"Duodecillion",
|
|
90
|
+
"Tredecillion",
|
|
91
|
+
"Quattuordecillion",
|
|
92
|
+
"Quindecillion",
|
|
93
|
+
"Sexdecillion",
|
|
94
|
+
"Septendecillion",
|
|
95
|
+
"Octodecillion",
|
|
96
|
+
"Novemdecillion",
|
|
97
|
+
"Vigintillion", # 1e63
|
|
98
|
+
"Unvigintillion",
|
|
99
|
+
"Duovigintillion",
|
|
100
|
+
"Tresvigintillion",
|
|
101
|
+
"Quattuorvigintillion",
|
|
102
|
+
"Quinvigintillion",
|
|
103
|
+
"Sesvigintillion",
|
|
104
|
+
"Septemvigintillion",
|
|
105
|
+
"Octovigintillion",
|
|
106
|
+
"Novemvigintillion",
|
|
107
|
+
"Trigintillion", # 1e93
|
|
108
|
+
"Untrigintillion",
|
|
109
|
+
"Duotrigintillion",
|
|
110
|
+
"Trestrigintillion",
|
|
111
|
+
"Quattuortrigintillion",
|
|
112
|
+
"Quintrigintillion",
|
|
113
|
+
"Sestrigintillion",
|
|
114
|
+
"Septentrigintillion",
|
|
115
|
+
"Octotrigintillion",
|
|
116
|
+
"Noventrigintillion", # 1e120
|
|
117
|
+
],
|
|
118
|
+
)
|
|
119
|
+
DATA_SIZE = UnitSuffixFactory(
|
|
120
|
+
1024,
|
|
121
|
+
["b", "Kb", "MB", "GB", "TB", "PB", "EB", "ZB", "YB", "BB"],
|
|
122
|
+
[
|
|
123
|
+
"byte",
|
|
124
|
+
"kilobyte",
|
|
125
|
+
"megabyte",
|
|
126
|
+
"gigabyte",
|
|
127
|
+
"terabyte",
|
|
128
|
+
"petabyte",
|
|
129
|
+
"exabyte",
|
|
130
|
+
"zetabyte",
|
|
131
|
+
"yottabyte",
|
|
132
|
+
"brontobyte",
|
|
133
|
+
],
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
@dataclass
|
|
138
|
+
class Decimal:
|
|
139
|
+
"""
|
|
140
|
+
Shorten large number
|
|
141
|
+
|
|
142
|
+
:param original_value: Value to shorten
|
|
143
|
+
:param base: Short by base (must be > 0)
|
|
144
|
+
:param suffixes: List of suffixes to use (ascending order)
|
|
145
|
+
:param factory: ``UnitSuffixFactory`` to use (will overwrite ``base`` and ``suffixes``)
|
|
146
|
+
:param suffix_full_name: Use suffix full name (default: False)
|
|
147
|
+
"""
|
|
148
|
+
|
|
149
|
+
original_value: int | float = field(repr=False)
|
|
150
|
+
base: Annotated[int, "positive", "not_zero"] = field(repr=False, default=1000)
|
|
151
|
+
suffixes: list[str] = field(repr=False, default_factory=list)
|
|
152
|
+
factory: UnitSuffixFactory | None = field(repr=False, default=None)
|
|
153
|
+
suffix_full_name: bool = field(repr=False, default=False)
|
|
154
|
+
# Post init
|
|
155
|
+
value: int | float = field(init=False)
|
|
156
|
+
suffix: str = field(init=False)
|
|
157
|
+
|
|
158
|
+
def __post_init__(self) -> None:
|
|
159
|
+
self._get_factory()
|
|
160
|
+
self.value, self.suffix = self._convert_decimal()
|
|
161
|
+
|
|
162
|
+
def __str__(self) -> str:
|
|
163
|
+
return self.to_text()
|
|
164
|
+
|
|
165
|
+
@classmethod
|
|
166
|
+
def number(cls, value: int | float, suffix_full_name: bool = False) -> Self:
|
|
167
|
+
"""Decimal for normal large number"""
|
|
168
|
+
return cls(
|
|
169
|
+
value,
|
|
170
|
+
factory=CommonUnitSuffixesFactory.NUMBER,
|
|
171
|
+
suffix_full_name=suffix_full_name,
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
@classmethod
|
|
175
|
+
def data_size(cls, value: int | float, suffix_full_name: bool = False) -> Self:
|
|
176
|
+
"""Decimal for data size"""
|
|
177
|
+
return cls(
|
|
178
|
+
value,
|
|
179
|
+
factory=CommonUnitSuffixesFactory.DATA_SIZE,
|
|
180
|
+
suffix_full_name=suffix_full_name,
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
@staticmethod
|
|
184
|
+
def scientific_short(value: int | float) -> str:
|
|
185
|
+
"""Short number in scientific format"""
|
|
186
|
+
return f"{value:.2e}"
|
|
187
|
+
|
|
188
|
+
def _get_factory(self) -> None:
|
|
189
|
+
if self.factory:
|
|
190
|
+
self.base = self.factory.base
|
|
191
|
+
self.suffixes = (
|
|
192
|
+
self.factory.full_name
|
|
193
|
+
if self.suffix_full_name
|
|
194
|
+
else self.factory.short_name
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
def _convert_decimal(self) -> tuple[float, str]:
|
|
198
|
+
"""Convert to smaller number"""
|
|
199
|
+
suffix = self.suffixes[0] if len(self.suffixes) > 0 else ""
|
|
200
|
+
unit = 1
|
|
201
|
+
for i, suffix in enumerate(self.suffixes):
|
|
202
|
+
unit = self.base**i
|
|
203
|
+
if self.original_value < unit * self.base:
|
|
204
|
+
break
|
|
205
|
+
output = self.original_value / unit
|
|
206
|
+
return output, suffix
|
|
207
|
+
|
|
208
|
+
def to_text(
|
|
209
|
+
self, decimal: int = 2, *, separator: str = " ", float_only: bool = True
|
|
210
|
+
) -> str:
|
|
211
|
+
"""
|
|
212
|
+
Convert to string
|
|
213
|
+
|
|
214
|
+
:param decimal: Round up to which decimal
|
|
215
|
+
:param separator: Character between value and suffix, default: ``" "``
|
|
216
|
+
:param float_only: Returns value as <float> instead of <int> when ``decimal = 0``
|
|
217
|
+
"""
|
|
218
|
+
val = self.value.__round__(decimal)
|
|
219
|
+
formatted_value = f"{val:,}"
|
|
220
|
+
if not float_only and decimal == 0:
|
|
221
|
+
formatted_value = f"{int(val):,}"
|
|
222
|
+
return f"{formatted_value}{separator}{self.suffix}"
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
# Run
|
|
226
|
+
###########################################################################
|
|
227
|
+
if __name__ == "__main__":
|
|
228
|
+
print(str(Decimal.number(10000)))
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Test: Everything
|
|
3
3
|
|
|
4
|
-
Version: 1.1.
|
|
5
|
-
Date updated:
|
|
4
|
+
Version: 1.1.27
|
|
5
|
+
Date updated: 01/02/2025 (dd/mm/yyyy)
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
# Library
|
|
@@ -103,6 +103,11 @@ from absfuyu.util.lunar import LunarCalendar
|
|
|
103
103
|
from absfuyu.util.path import Directory, SaveFileAs
|
|
104
104
|
from absfuyu.util.performance import Checker, function_debug, measure_performance, retry
|
|
105
105
|
from absfuyu.util.pkl import Pickler
|
|
106
|
+
from absfuyu.util.shorten_number import (
|
|
107
|
+
CommonUnitSuffixesFactory,
|
|
108
|
+
Decimal,
|
|
109
|
+
UnitSuffixFactory,
|
|
110
|
+
)
|
|
106
111
|
from absfuyu.util.zipped import Zipper
|
|
107
112
|
from absfuyu.version import (
|
|
108
113
|
Bumper,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Test: Tarot
|
|
3
3
|
|
|
4
|
-
Version: 1.0.
|
|
5
|
-
Date updated:
|
|
4
|
+
Version: 1.0.1
|
|
5
|
+
Date updated: 16/01/2025 (dd/mm/yyyy)
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
# Library
|
|
@@ -15,4 +15,4 @@ from absfuyu.fun.tarot import Tarot, TarotCard
|
|
|
15
15
|
# Test
|
|
16
16
|
###########################################################################
|
|
17
17
|
def test_tarot():
|
|
18
|
-
assert
|
|
18
|
+
assert isinstance(Tarot().random_card(), TarotCard)
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Test: Util
|
|
3
3
|
|
|
4
|
-
Version: 1.
|
|
5
|
-
Date updated:
|
|
4
|
+
Version: 1.2.0
|
|
5
|
+
Date updated: 01/02/2025 (dd/mm/yyyy)
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
import sys
|
|
@@ -14,6 +14,7 @@ from absfuyu.util import set_max, set_min, set_min_max
|
|
|
14
14
|
from absfuyu.util.api import APIRequest, PingResult, ping_windows
|
|
15
15
|
from absfuyu.util.json_method import JsonFile
|
|
16
16
|
from absfuyu.util.path import Directory
|
|
17
|
+
from absfuyu.util.shorten_number import CommonUnitSuffixesFactory, Decimal
|
|
17
18
|
|
|
18
19
|
|
|
19
20
|
# MARK: util
|
|
@@ -48,11 +49,13 @@ class TestUtilAPI:
|
|
|
48
49
|
# No internet
|
|
49
50
|
assert instance
|
|
50
51
|
|
|
52
|
+
@pytest.mark.skipif(
|
|
53
|
+
sys.platform not in ["win32", "cygwin"],
|
|
54
|
+
reason="Not applicable on Linux and MacOS",
|
|
55
|
+
) # windows only
|
|
51
56
|
def test_ping_windows(self) -> None:
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
assert isinstance(res[0], PingResult)
|
|
55
|
-
assert True
|
|
57
|
+
res = ping_windows(["google.com"], 1)
|
|
58
|
+
assert isinstance(res[0], PingResult)
|
|
56
59
|
|
|
57
60
|
|
|
58
61
|
# MARK: json
|
|
@@ -74,3 +77,28 @@ class TestUtilPath:
|
|
|
74
77
|
def test_list_structure(self) -> None:
|
|
75
78
|
instance = Directory(source_path=CORE_PATH)
|
|
76
79
|
assert instance.list_structure_pkg()
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
# MARK: shorten number
|
|
83
|
+
@pytest.mark.abs_util
|
|
84
|
+
class TestUtilShortenNumber:
|
|
85
|
+
"""absfuyu.util.shorten_number"""
|
|
86
|
+
|
|
87
|
+
@pytest.mark.parametrize(["value", "output"], [(1000, 1.0), (1000000, 1.0)])
|
|
88
|
+
def test_number(self, value: int | float, output: float) -> None:
|
|
89
|
+
ins = Decimal.number(value)
|
|
90
|
+
assert ins.value == output
|
|
91
|
+
|
|
92
|
+
def test_number2(self) -> None:
|
|
93
|
+
fac = CommonUnitSuffixesFactory.NUMBER
|
|
94
|
+
unit = 1
|
|
95
|
+
for i, suffix in enumerate(fac.short_name):
|
|
96
|
+
unit = fac.base**i
|
|
97
|
+
assert Decimal.number(unit).suffix == suffix
|
|
98
|
+
|
|
99
|
+
def test_data_size(self) -> None:
|
|
100
|
+
fac = CommonUnitSuffixesFactory.DATA_SIZE
|
|
101
|
+
unit = 1
|
|
102
|
+
for i, suffix in enumerate(fac.short_name):
|
|
103
|
+
unit = fac.base**i
|
|
104
|
+
assert Decimal.data_size(unit).suffix == suffix
|
|
@@ -6,7 +6,6 @@ Date updated: 06/04/2024 (dd/mm/yyyy)
|
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
from itertools import product
|
|
9
|
-
from typing import List, Tuple, Union
|
|
10
9
|
|
|
11
10
|
import pytest
|
|
12
11
|
|
|
@@ -20,10 +19,10 @@ class TestVersion:
|
|
|
20
19
|
)
|
|
21
20
|
def test_init(
|
|
22
21
|
self,
|
|
23
|
-
major:
|
|
24
|
-
minor:
|
|
25
|
-
patch:
|
|
26
|
-
serial:
|
|
22
|
+
major: int | str,
|
|
23
|
+
minor: int | str,
|
|
24
|
+
patch: int | str,
|
|
25
|
+
serial: int | str,
|
|
27
26
|
) -> None:
|
|
28
27
|
try:
|
|
29
28
|
_ = Version(major, minor, patch, ReleaseLevel.DEV, serial)
|
|
@@ -71,24 +70,24 @@ class TestVersion:
|
|
|
71
70
|
|
|
72
71
|
|
|
73
72
|
# Bumper
|
|
74
|
-
def list_of_bumper_bump_test() ->
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
bumper_list:
|
|
73
|
+
def list_of_bumper_bump_test() -> list[
|
|
74
|
+
tuple[tuple[int, int, int, str, int], str, str, str]
|
|
75
|
+
]:
|
|
76
|
+
bumper_list: list[tuple[int, int, int, str, int]] = [
|
|
78
77
|
(1, 0, 0, ReleaseLevel.FINAL, 0),
|
|
79
78
|
(1, 3, 2, ReleaseLevel.FINAL, 0),
|
|
80
79
|
(2, 4, 6, ReleaseLevel.RC, 0),
|
|
81
80
|
(2, 4, 6, ReleaseLevel.DEV, 0),
|
|
82
81
|
]
|
|
83
|
-
release_options:
|
|
82
|
+
release_options: list[str] = [
|
|
84
83
|
ReleaseOption.MAJOR,
|
|
85
84
|
ReleaseOption.MINOR,
|
|
86
85
|
ReleaseOption.PATCH,
|
|
87
86
|
]
|
|
88
|
-
release_levels:
|
|
87
|
+
release_levels: list[str] = [ReleaseLevel.FINAL, ReleaseLevel.DEV, ReleaseLevel.RC]
|
|
89
88
|
merged = list(product(bumper_list, release_options, release_levels))
|
|
90
89
|
# TODO: Improve this
|
|
91
|
-
result_list:
|
|
90
|
+
result_list: list[str] = [
|
|
92
91
|
# 1.0.0
|
|
93
92
|
"2.0.0", # major final
|
|
94
93
|
"2.0.0.dev0", # major dev
|
|
@@ -133,7 +132,7 @@ def list_of_bumper_bump_test() -> (
|
|
|
133
132
|
if not len(result_list) == len(merged):
|
|
134
133
|
# Check length
|
|
135
134
|
raise ValueError("length of result_list is not in correct length")
|
|
136
|
-
out:
|
|
135
|
+
out: list[tuple[Bumper, str, str, str]] = [
|
|
137
136
|
(x[0], x[1], x[2], result_list[i]) for i, x in enumerate(merged)
|
|
138
137
|
]
|
|
139
138
|
return out
|
|
@@ -146,7 +145,7 @@ class TestBumper:
|
|
|
146
145
|
)
|
|
147
146
|
def test_bump(
|
|
148
147
|
self,
|
|
149
|
-
bumper:
|
|
148
|
+
bumper: tuple[int, int, int, str, int],
|
|
150
149
|
release_option: str,
|
|
151
150
|
release_channel: str,
|
|
152
151
|
desired_output: str,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|