absfuyu 3.4.0__tar.gz → 4.0.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-3.4.0 → absfuyu-4.0.0}/PKG-INFO +5 -9
- {absfuyu-3.4.0 → absfuyu-4.0.0}/pyproject.toml +15 -12
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/__init__.py +1 -1
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/cli/do_group.py +14 -2
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/config/__init__.py +13 -13
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/core.py +5 -16
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/extensions/extra/data_analysis.py +74 -28
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/fun/__init__.py +24 -23
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/fun/tarot.py +6 -7
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/game/__init__.py +1 -1
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/game/sudoku.py +6 -5
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/game/tictactoe.py +4 -4
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/general/data_extension.py +41 -60
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/pkg_data/__init__.py +13 -20
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/tools/converter.py +9 -10
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/util/__init__.py +13 -14
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/util/api.py +7 -7
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/util/json_method.py +9 -9
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/util/lunar.py +7 -8
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/util/path.py +23 -21
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/util/performance.py +8 -8
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/util/zipped.py +18 -6
- {absfuyu-3.4.0 → absfuyu-4.0.0}/tests/test_data_analysis.py +1 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/tests/test_fun.py +3 -3
- {absfuyu-3.4.0 → absfuyu-4.0.0}/.gitignore +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/LICENSE +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/README.md +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/dev_requirements.txt +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/docs/Makefile +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/docs/conf.py +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/docs/index.rst +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/docs/info.md +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/docs/make.bat +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/docs/modules.rst +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/images/repository-image-crop.png +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/images/repository-image-white.png +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/images/repository-image.png +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/__main__.py +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/cli/__init__.py +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/cli/color.py +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/cli/config_group.py +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/cli/game_group.py +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/config/config.json +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/everything.py +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/extensions/__init__.py +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/extensions/beautiful.py +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/extensions/dev/__init__.py +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/extensions/dev/password_hash.py +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/extensions/dev/passwordlib.py +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/extensions/dev/project_starter.py +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/extensions/dev/shutdownizer.py +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/extensions/extra/__init__.py +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/fun/WGS.py +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/game/game_stat.py +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/game/wordle.py +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/general/__init__.py +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/general/content.py +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/general/generator.py +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/general/human.py +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/logger.py +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/pkg_data/chemistry.pkl +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/pkg_data/tarot.pkl +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/py.typed +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/sort.py +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/tools/__init__.py +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/tools/keygen.py +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/tools/obfuscator.py +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/tools/stats.py +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/tools/web.py +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/util/pkl.py +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/version.py +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/tests/__init__.py +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/tests/conftest.py +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/tests/test_beautiful.py +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/tests/test_config.py +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/tests/test_data_extension.py +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/tests/test_everything.py +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/tests/test_extensions.py +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/tests/test_game.py +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/tests/test_generator.py +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/tests/test_logger.py +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/tests/test_passwordlib.py +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/tests/test_pkg_data.py +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/tests/test_tarot.py +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/tests/test_tools.py +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/tests/test_util.py +0 -0
- {absfuyu-3.4.0 → absfuyu-4.0.0}/tests/test_version.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: absfuyu
|
|
3
|
-
Version:
|
|
3
|
+
Version: 4.0.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/
|
|
@@ -18,24 +18,20 @@ Classifier: Natural Language :: English
|
|
|
18
18
|
Classifier: Operating System :: OS Independent
|
|
19
19
|
Classifier: Programming Language :: Python :: 3
|
|
20
20
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
21
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
22
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
23
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
24
21
|
Classifier: Programming Language :: Python :: 3.11
|
|
25
22
|
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
26
24
|
Classifier: Topic :: Software Development :: Libraries
|
|
27
25
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
28
26
|
Classifier: Topic :: Utilities
|
|
29
|
-
Requires-Python: <4,>=3.
|
|
27
|
+
Requires-Python: <4,>=3.11
|
|
30
28
|
Requires-Dist: bs4
|
|
31
29
|
Requires-Dist: click>=8.0.0
|
|
32
30
|
Requires-Dist: colorama
|
|
33
31
|
Requires-Dist: deprecated
|
|
34
|
-
Requires-Dist: importlib-resources; python_version < '3.10'
|
|
35
32
|
Requires-Dist: python-dateutil
|
|
36
33
|
Requires-Dist: requests
|
|
37
|
-
Requires-Dist:
|
|
38
|
-
Requires-Dist: typing-extensions>=4.0.1; python_version < '3.11'
|
|
34
|
+
Requires-Dist: typing-extensions>=4.5.0; python_version < '3.12'
|
|
39
35
|
Requires-Dist: unidecode
|
|
40
36
|
Provides-Extra: beautiful
|
|
41
37
|
Requires-Dist: rich; extra == 'beautiful'
|
|
@@ -18,17 +18,15 @@ build-backend = "hatchling.build"
|
|
|
18
18
|
name = "absfuyu"
|
|
19
19
|
description = "A small collection of code"
|
|
20
20
|
readme = { "file" = "README.md", "content-type" = "text/markdown" }
|
|
21
|
-
requires-python = ">=3.
|
|
21
|
+
requires-python = ">=3.11, <4"
|
|
22
22
|
license = { text = "MIT License" }
|
|
23
23
|
keywords = ["utilities"]
|
|
24
24
|
authors = [{ name = "somewhatcold (AbsoluteWinter)" }]
|
|
25
25
|
classifiers = [
|
|
26
26
|
"Programming Language :: Python :: 3",
|
|
27
|
-
"Programming Language :: Python :: 3.8",
|
|
28
|
-
"Programming Language :: Python :: 3.9",
|
|
29
|
-
"Programming Language :: Python :: 3.10",
|
|
30
27
|
"Programming Language :: Python :: 3.11",
|
|
31
28
|
"Programming Language :: Python :: 3.12",
|
|
29
|
+
"Programming Language :: Python :: 3.13",
|
|
32
30
|
"Programming Language :: Python :: 3 :: Only",
|
|
33
31
|
"License :: OSI Approved :: MIT License",
|
|
34
32
|
"Operating System :: OS Independent",
|
|
@@ -46,11 +44,9 @@ dependencies = [
|
|
|
46
44
|
"click>=8.0.0",
|
|
47
45
|
"colorama",
|
|
48
46
|
"Deprecated",
|
|
49
|
-
"importlib_resources; python_version < '3.10'",
|
|
50
47
|
"python-dateutil",
|
|
51
48
|
"requests",
|
|
52
|
-
"
|
|
53
|
-
"typing_extensions>=4.0.1; python_version < '3.11'",
|
|
49
|
+
"typing_extensions>=4.5.0; python_version < '3.12'",
|
|
54
50
|
"unidecode",
|
|
55
51
|
]
|
|
56
52
|
|
|
@@ -113,7 +109,7 @@ Use `hatch run all:install` when occur "no module named" error
|
|
|
113
109
|
install = "pip install -e .[full]" # This command fix "no module named"
|
|
114
110
|
|
|
115
111
|
[[tool.hatch.envs.all.matrix]] # hatch env run -e all test
|
|
116
|
-
python = ["3.
|
|
112
|
+
python = ["3.11", "3.12", "3.13"]
|
|
117
113
|
|
|
118
114
|
[tool.hatch.envs.types]
|
|
119
115
|
dependencies = ["mypy>=1.0.0"]
|
|
@@ -247,7 +243,7 @@ no_implicit_reexport = true
|
|
|
247
243
|
[tool.ruff]
|
|
248
244
|
line-length = 88
|
|
249
245
|
indent-width = 4
|
|
250
|
-
target-version = "
|
|
246
|
+
target-version = "py311"
|
|
251
247
|
include = ["pyproject.toml", "src/**", "tests/**"]
|
|
252
248
|
|
|
253
249
|
[tool.ruff.format]
|
|
@@ -263,19 +259,26 @@ ignore = [
|
|
|
263
259
|
"E266", # too many leading "#" for block comment
|
|
264
260
|
"E501", # line too long
|
|
265
261
|
"W291", # trailing whitespace
|
|
262
|
+
"B905", # `zip()` without an explicit `strict=` parameter
|
|
266
263
|
]
|
|
267
264
|
|
|
268
265
|
[tool.ruff.lint.per-file-ignores]
|
|
269
266
|
"__init__.py" = ["E402", "F401"] # module level import not at top of file
|
|
270
267
|
"core.py" = ["E402"]
|
|
271
|
-
"human.py" = [
|
|
272
|
-
"
|
|
268
|
+
"human.py" = [
|
|
269
|
+
"E741", # Ambiguous variable name
|
|
270
|
+
]
|
|
271
|
+
"test_everything.py" = [
|
|
272
|
+
"F403", # unable to detect undefined names
|
|
273
|
+
]
|
|
273
274
|
"test_version.py" = [
|
|
274
275
|
# Within an `except` clause, raise exceptions with `raise ... from err`
|
|
275
276
|
# or `raise ... from None` to distinguish them from errors in exception handling
|
|
276
277
|
"B904",
|
|
277
278
|
]
|
|
278
|
-
"tests/*" = [
|
|
279
|
+
"tests/*" = [
|
|
280
|
+
"F401", # imported but unused
|
|
281
|
+
]
|
|
279
282
|
|
|
280
283
|
# MARK: TOOL: black
|
|
281
284
|
[tool.black]
|
|
@@ -3,8 +3,8 @@ ABSFUYU CLI
|
|
|
3
3
|
-----------
|
|
4
4
|
Do
|
|
5
5
|
|
|
6
|
-
Version: 1.
|
|
7
|
-
Date updated:
|
|
6
|
+
Version: 1.2.0
|
|
7
|
+
Date updated: 07/01/2025 (dd/mm/yyyy)
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
__all__ = ["do_group"]
|
|
@@ -17,6 +17,7 @@ from absfuyu import __title__
|
|
|
17
17
|
from absfuyu.cli.color import COLOR
|
|
18
18
|
from absfuyu.core import __package_feature__
|
|
19
19
|
from absfuyu.general.human import Human2
|
|
20
|
+
from absfuyu.util.zipped import Zipper
|
|
20
21
|
from absfuyu.version import PkgVersion
|
|
21
22
|
|
|
22
23
|
|
|
@@ -85,6 +86,16 @@ def info(date: str) -> None:
|
|
|
85
86
|
print(instance.info())
|
|
86
87
|
|
|
87
88
|
|
|
89
|
+
@click.command(name="unzip")
|
|
90
|
+
@click.argument("dir", type=str)
|
|
91
|
+
def unzip_files_in_dir(dir: str) -> None:
|
|
92
|
+
"""Unzip every files in directory"""
|
|
93
|
+
|
|
94
|
+
engine = Zipper(dir)
|
|
95
|
+
engine.unzip()
|
|
96
|
+
print("Done")
|
|
97
|
+
|
|
98
|
+
|
|
88
99
|
@click.group(name="do")
|
|
89
100
|
def do_group() -> None:
|
|
90
101
|
"""Perform functionalities"""
|
|
@@ -96,3 +107,4 @@ do_group.add_command(install)
|
|
|
96
107
|
do_group.add_command(advice)
|
|
97
108
|
do_group.add_command(fs)
|
|
98
109
|
do_group.add_command(info)
|
|
110
|
+
do_group.add_command(unzip_files_in_dir)
|
|
@@ -3,8 +3,8 @@ Absfuyu: Configuration
|
|
|
3
3
|
----------------------
|
|
4
4
|
Package configuration module
|
|
5
5
|
|
|
6
|
-
Version: 2.0.
|
|
7
|
-
Date updated:
|
|
6
|
+
Version: 2.0.5
|
|
7
|
+
Date updated: 14/11/2024 (dd/mm/yyyy)
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
# Module level
|
|
@@ -19,7 +19,7 @@ __all__ = [
|
|
|
19
19
|
# Library
|
|
20
20
|
###########################################################################
|
|
21
21
|
from pathlib import Path
|
|
22
|
-
from typing import Any,
|
|
22
|
+
from typing import Any, TypedDict
|
|
23
23
|
|
|
24
24
|
from absfuyu.core import CONFIG_PATH
|
|
25
25
|
from absfuyu.util.json_method import JsonFile
|
|
@@ -55,7 +55,7 @@ class ConfigFormat(TypedDict):
|
|
|
55
55
|
:type version: VersionDictFormat
|
|
56
56
|
"""
|
|
57
57
|
|
|
58
|
-
setting:
|
|
58
|
+
setting: dict[str, SettingDictFormat]
|
|
59
59
|
|
|
60
60
|
|
|
61
61
|
# Class
|
|
@@ -82,7 +82,7 @@ class Setting:
|
|
|
82
82
|
return self.__str__()
|
|
83
83
|
|
|
84
84
|
@classmethod
|
|
85
|
-
def from_dict(cls, dict_data:
|
|
85
|
+
def from_dict(cls, dict_data: dict[str, SettingDictFormat]):
|
|
86
86
|
"""
|
|
87
87
|
Convert ``dict`` into ``Setting`` (``len==1`` only)
|
|
88
88
|
"""
|
|
@@ -104,11 +104,11 @@ class Setting:
|
|
|
104
104
|
"""Update current value"""
|
|
105
105
|
self.value = value
|
|
106
106
|
|
|
107
|
-
def to_dict(self) ->
|
|
107
|
+
def to_dict(self) -> dict[str, SettingDictFormat]:
|
|
108
108
|
"""
|
|
109
109
|
Convert ``Setting`` into ``dict``
|
|
110
110
|
"""
|
|
111
|
-
output:
|
|
111
|
+
output: dict[str, SettingDictFormat] = {
|
|
112
112
|
self.name: {"default": self.default, "help": self.help, "value": self.value}
|
|
113
113
|
}
|
|
114
114
|
return output
|
|
@@ -119,7 +119,7 @@ class Config:
|
|
|
119
119
|
Config handling
|
|
120
120
|
"""
|
|
121
121
|
|
|
122
|
-
def __init__(self, config_file: Path, name:
|
|
122
|
+
def __init__(self, config_file: Path, name: str | None = None) -> None:
|
|
123
123
|
"""
|
|
124
124
|
config_file: Path to `.json` config file
|
|
125
125
|
"""
|
|
@@ -132,7 +132,7 @@ class Config:
|
|
|
132
132
|
self.name = self.config_path.name
|
|
133
133
|
|
|
134
134
|
# Data
|
|
135
|
-
self.settings:
|
|
135
|
+
self.settings: list[Setting] = None # type: ignore
|
|
136
136
|
self._fetch_data() # Load data
|
|
137
137
|
|
|
138
138
|
def __str__(self) -> str:
|
|
@@ -145,7 +145,7 @@ class Config:
|
|
|
145
145
|
def _fetch_data(self) -> None:
|
|
146
146
|
"""Load data from ``self.config_file`` file"""
|
|
147
147
|
data: dict = self.json_engine.load_json()
|
|
148
|
-
settings:
|
|
148
|
+
settings: dict[str, SettingDictFormat] = data.get("setting") # type: ignore
|
|
149
149
|
self.settings = [Setting.from_dict({k: v}) for k, v in settings.items()]
|
|
150
150
|
|
|
151
151
|
def _prepare_data(self) -> ConfigFormat:
|
|
@@ -164,7 +164,7 @@ class Config:
|
|
|
164
164
|
|
|
165
165
|
# Setting method
|
|
166
166
|
@property
|
|
167
|
-
def setting_list(self) ->
|
|
167
|
+
def setting_list(self) -> list[str]:
|
|
168
168
|
"""List of name of available settings"""
|
|
169
169
|
return [setting.name for setting in self.settings]
|
|
170
170
|
|
|
@@ -183,7 +183,7 @@ class Config:
|
|
|
183
183
|
[setting.reset() for setting in self.settings] # type: ignore
|
|
184
184
|
self.save()
|
|
185
185
|
|
|
186
|
-
def show_settings(self) ->
|
|
186
|
+
def show_settings(self) -> list[Setting]:
|
|
187
187
|
"""
|
|
188
188
|
Returns a list of available settings
|
|
189
189
|
(wrapper for ``Config.settings``)
|
|
@@ -276,7 +276,7 @@ class Config:
|
|
|
276
276
|
|
|
277
277
|
# Init
|
|
278
278
|
###########################################################################
|
|
279
|
-
ABSFUYU_CONFIG = Config(CONFIG_PATH)
|
|
279
|
+
ABSFUYU_CONFIG = Config(CONFIG_PATH) # type: ignore
|
|
280
280
|
|
|
281
281
|
# TODO: Create a config file when not available [W.I.P]
|
|
282
282
|
# _settings = [
|
|
@@ -3,8 +3,8 @@ Absfuyu: Core
|
|
|
3
3
|
-------------
|
|
4
4
|
Contain type hints and other stuffs
|
|
5
5
|
|
|
6
|
-
Version: 2.2.
|
|
7
|
-
Date updated: 14/
|
|
6
|
+
Version: 2.2.1
|
|
7
|
+
Date updated: 14/11/2024 (dd/mm/yyyy)
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
# Module Package
|
|
@@ -21,18 +21,7 @@ __all__ = [
|
|
|
21
21
|
__package_feature__ = ["beautiful", "extra", "res", "full", "dev"]
|
|
22
22
|
|
|
23
23
|
|
|
24
|
-
from
|
|
25
|
-
|
|
26
|
-
# import sys
|
|
27
|
-
# from sys import version_info as _python_version
|
|
28
|
-
|
|
29
|
-
# if sys.version_info.minor >= 10:
|
|
30
|
-
# from importlib.resources import files
|
|
31
|
-
# else:
|
|
32
|
-
# try:
|
|
33
|
-
# from importlib_resources import files
|
|
34
|
-
# except:
|
|
35
|
-
# raise ImportError("Please install importlib-resources")
|
|
24
|
+
from importlib.resources import files
|
|
36
25
|
|
|
37
26
|
|
|
38
27
|
class CLITextColor:
|
|
@@ -50,7 +39,7 @@ class CLITextColor:
|
|
|
50
39
|
RESET = "\x1b[39m"
|
|
51
40
|
|
|
52
41
|
|
|
53
|
-
CORE_PATH = Path(__file__).parent.absolute()
|
|
54
|
-
|
|
42
|
+
# CORE_PATH = Path(__file__).parent.absolute()
|
|
43
|
+
CORE_PATH = files("absfuyu")
|
|
55
44
|
CONFIG_PATH = CORE_PATH.joinpath("config", "config.json")
|
|
56
45
|
DATA_PATH = CORE_PATH.joinpath("pkg_data")
|
|
@@ -3,8 +3,8 @@ Absfuyu: Data Analysis [W.I.P]
|
|
|
3
3
|
------------------------------
|
|
4
4
|
Extension for ``pd.DataFrame``
|
|
5
5
|
|
|
6
|
-
Version: 2.
|
|
7
|
-
Date updated:
|
|
6
|
+
Version: 2.2.0
|
|
7
|
+
Date updated: 29/11/2024 (dd/mm/yyyy)
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
# Module level
|
|
@@ -30,7 +30,7 @@ import string
|
|
|
30
30
|
from collections import deque
|
|
31
31
|
from datetime import datetime
|
|
32
32
|
from itertools import chain, product
|
|
33
|
-
from typing import Any,
|
|
33
|
+
from typing import Any, Literal, NamedTuple, Self
|
|
34
34
|
|
|
35
35
|
# import matplotlib.pyplot as plt
|
|
36
36
|
# from scipy import stats
|
|
@@ -49,7 +49,7 @@ from absfuyu.util import set_min, set_min_max
|
|
|
49
49
|
###########################################################################
|
|
50
50
|
@deprecated(reason="Not needed", version="3.1.0")
|
|
51
51
|
@sphinx_deprecated(reason="Not needed", version="3.1.0")
|
|
52
|
-
def summary(data:
|
|
52
|
+
def summary(data: list | np.ndarray): # del this
|
|
53
53
|
"""
|
|
54
54
|
Quick summary of data
|
|
55
55
|
|
|
@@ -78,7 +78,7 @@ def summary(data: Union[list, np.ndarray]): # del this
|
|
|
78
78
|
return output
|
|
79
79
|
|
|
80
80
|
|
|
81
|
-
def equalize_df(data:
|
|
81
|
+
def equalize_df(data: dict[str, list], fillna=np.nan) -> dict[str, list]:
|
|
82
82
|
"""
|
|
83
83
|
Make all list in dict have equal length to make pd.DataFrame
|
|
84
84
|
|
|
@@ -182,14 +182,14 @@ class CityData(NamedTuple):
|
|
|
182
182
|
area: str
|
|
183
183
|
|
|
184
184
|
@staticmethod
|
|
185
|
-
def _sample_city_data(size: int = 100) ->
|
|
185
|
+
def _sample_city_data(size: int = 100) -> list["CityData"]:
|
|
186
186
|
"""
|
|
187
187
|
Generate sample city data (testing purpose)
|
|
188
188
|
"""
|
|
189
189
|
sample_range = 10 ** len(str(size))
|
|
190
190
|
|
|
191
191
|
# Serial list
|
|
192
|
-
serials:
|
|
192
|
+
serials: list[str] = []
|
|
193
193
|
while len(serials) != size: # Unique serial
|
|
194
194
|
serial = random.randint(0, sample_range - 1)
|
|
195
195
|
serial = str(serial).rjust(len(str(size)), "0") # type: ignore
|
|
@@ -232,7 +232,9 @@ class SplittedDF(NamedTuple):
|
|
|
232
232
|
df_na: pd.DataFrame
|
|
233
233
|
|
|
234
234
|
@staticmethod
|
|
235
|
-
def concat_df(
|
|
235
|
+
def concat_df(
|
|
236
|
+
df_list: list[pd.DataFrame], join: Literal["inner", "outer"] = "inner"
|
|
237
|
+
) -> pd.DataFrame:
|
|
236
238
|
"""
|
|
237
239
|
Concat the list of DataFrame (static method)
|
|
238
240
|
|
|
@@ -254,7 +256,7 @@ class SplittedDF(NamedTuple):
|
|
|
254
256
|
df.drop(columns=["index"], inplace=True)
|
|
255
257
|
return df
|
|
256
258
|
|
|
257
|
-
def concat(self, join:
|
|
259
|
+
def concat(self, join: Literal["inner", "outer"] = "inner") -> pd.DataFrame:
|
|
258
260
|
"""
|
|
259
261
|
Concat the splitted DataFrame
|
|
260
262
|
|
|
@@ -272,7 +274,7 @@ class SplittedDF(NamedTuple):
|
|
|
272
274
|
return self.concat_df(self, join=join) # type: ignore
|
|
273
275
|
|
|
274
276
|
@staticmethod
|
|
275
|
-
def divide_dataframe(df: pd.DataFrame, by_column: str) ->
|
|
277
|
+
def divide_dataframe(df: pd.DataFrame, by_column: str) -> list[pd.DataFrame]:
|
|
276
278
|
"""
|
|
277
279
|
Divide DataFrame into a list of DataFrame
|
|
278
280
|
|
|
@@ -400,7 +402,7 @@ class MatplotlibFormatString:
|
|
|
400
402
|
Color = _DictToAtrr(COLOR_LIST, key_as_atrribute=False)
|
|
401
403
|
|
|
402
404
|
@staticmethod
|
|
403
|
-
def all_format_string() ->
|
|
405
|
+
def all_format_string() -> list[PLTFormatString]:
|
|
404
406
|
fmt_str = [
|
|
405
407
|
__class__.MARKER_LIST, # type: ignore
|
|
406
408
|
__class__.LINE_STYLE_LIST, # type: ignore
|
|
@@ -427,7 +429,7 @@ class DataAnalystDataFrame(pd.DataFrame):
|
|
|
427
429
|
# Support
|
|
428
430
|
# ================================================================
|
|
429
431
|
# Rearrange column
|
|
430
|
-
def rearrange_column(self, insert_to_col: str, num_of_cols: int = 1):
|
|
432
|
+
def rearrange_column(self, insert_to_col: str, num_of_cols: int = 1) -> Self:
|
|
431
433
|
"""
|
|
432
434
|
Move right-most columns to selected position
|
|
433
435
|
|
|
@@ -456,7 +458,7 @@ class DataAnalystDataFrame(pd.DataFrame):
|
|
|
456
458
|
return self
|
|
457
459
|
|
|
458
460
|
# Drop a list of column
|
|
459
|
-
def drop_columns(self, columns:
|
|
461
|
+
def drop_columns(self, columns: list[str]) -> Self:
|
|
460
462
|
"""
|
|
461
463
|
Drop columns in DataFrame
|
|
462
464
|
|
|
@@ -479,7 +481,7 @@ class DataAnalystDataFrame(pd.DataFrame):
|
|
|
479
481
|
return self
|
|
480
482
|
|
|
481
483
|
# Drop right-most columns
|
|
482
|
-
def drop_rightmost(self, num_of_cols: int = 1):
|
|
484
|
+
def drop_rightmost(self, num_of_cols: int = 1) -> Self:
|
|
483
485
|
"""
|
|
484
486
|
Drop ``num_of_cols`` right-most columns
|
|
485
487
|
|
|
@@ -508,7 +510,7 @@ class DataAnalystDataFrame(pd.DataFrame):
|
|
|
508
510
|
return self
|
|
509
511
|
|
|
510
512
|
# Add blank column
|
|
511
|
-
def add_blank_column(self, column_name: str, fill: Any):
|
|
513
|
+
def add_blank_column(self, column_name: str, fill: Any) -> Self:
|
|
512
514
|
"""
|
|
513
515
|
Add a blank column
|
|
514
516
|
|
|
@@ -534,10 +536,10 @@ class DataAnalystDataFrame(pd.DataFrame):
|
|
|
534
536
|
def convert_city(
|
|
535
537
|
self,
|
|
536
538
|
city_column: str,
|
|
537
|
-
city_list:
|
|
539
|
+
city_list: list[CityData],
|
|
538
540
|
*,
|
|
539
541
|
mode: str = "ra",
|
|
540
|
-
):
|
|
542
|
+
) -> Self:
|
|
541
543
|
"""
|
|
542
544
|
Get ``region`` and ``area`` of a city
|
|
543
545
|
|
|
@@ -588,7 +590,7 @@ class DataAnalystDataFrame(pd.DataFrame):
|
|
|
588
590
|
return self.rearrange_column(city_column, col_counter)
|
|
589
591
|
|
|
590
592
|
# Date related
|
|
591
|
-
def add_date_from_month(self, month_column: str, *, col_name: str = "date"):
|
|
593
|
+
def add_date_from_month(self, month_column: str, *, col_name: str = "date") -> Self:
|
|
592
594
|
"""
|
|
593
595
|
Add dummy ``date`` column from ``month`` column
|
|
594
596
|
|
|
@@ -614,7 +616,7 @@ class DataAnalystDataFrame(pd.DataFrame):
|
|
|
614
616
|
# Rearrange
|
|
615
617
|
return self.rearrange_column(month_column)
|
|
616
618
|
|
|
617
|
-
def add_detail_date(self, date_column: str, mode: str = "dwmy"):
|
|
619
|
+
def add_detail_date(self, date_column: str, mode: str = "dwmy") -> Self:
|
|
618
620
|
"""
|
|
619
621
|
Add these columns from ``date_column``:
|
|
620
622
|
- ``date`` (won't add if ``date_column`` value is ``"date"``)
|
|
@@ -668,8 +670,12 @@ class DataAnalystDataFrame(pd.DataFrame):
|
|
|
668
670
|
return self.rearrange_column(date_column, col_counter)
|
|
669
671
|
|
|
670
672
|
def delta_date(
|
|
671
|
-
self,
|
|
672
|
-
|
|
673
|
+
self,
|
|
674
|
+
date_column: str,
|
|
675
|
+
mode: Literal["now", "between_row"] = "now",
|
|
676
|
+
*,
|
|
677
|
+
col_name: str = "delta_date",
|
|
678
|
+
) -> Self:
|
|
673
679
|
"""
|
|
674
680
|
Calculate date interval
|
|
675
681
|
|
|
@@ -682,7 +688,7 @@ class DataAnalystDataFrame(pd.DataFrame):
|
|
|
682
688
|
| Mode to calculate
|
|
683
689
|
| ``"between_row"``: Calculate date interval between each row
|
|
684
690
|
| ``"now"``: Calculate date interval to current date
|
|
685
|
-
| (Default: ``"
|
|
691
|
+
| (Default: ``"now"``)
|
|
686
692
|
|
|
687
693
|
col_name : str
|
|
688
694
|
| New delta date column name
|
|
@@ -714,7 +720,7 @@ class DataAnalystDataFrame(pd.DataFrame):
|
|
|
714
720
|
# Fill missing value
|
|
715
721
|
def fill_missing_values(
|
|
716
722
|
self, column_name: str, fill: Any = np.nan, *, fill_when_not_exist: Any = np.nan
|
|
717
|
-
):
|
|
723
|
+
) -> Self:
|
|
718
724
|
"""
|
|
719
725
|
Fill missing values in specified column
|
|
720
726
|
|
|
@@ -771,11 +777,11 @@ class DataAnalystDataFrame(pd.DataFrame):
|
|
|
771
777
|
def threshold_filter(
|
|
772
778
|
self,
|
|
773
779
|
destination_column: str,
|
|
774
|
-
threshold:
|
|
780
|
+
threshold: int | float = 10,
|
|
775
781
|
*,
|
|
776
|
-
top:
|
|
782
|
+
top: int | None = None,
|
|
777
783
|
replace_with: Any = "Other",
|
|
778
|
-
):
|
|
784
|
+
) -> Self:
|
|
779
785
|
"""
|
|
780
786
|
Filter out percentage of data that smaller than the ``threshold``,
|
|
781
787
|
replace all of the smaller data to ``replace_with``.
|
|
@@ -972,7 +978,7 @@ class DataAnalystDataFrame(pd.DataFrame):
|
|
|
972
978
|
|
|
973
979
|
# Help
|
|
974
980
|
@staticmethod
|
|
975
|
-
def dadf_help() ->
|
|
981
|
+
def dadf_help() -> list[str]:
|
|
976
982
|
"""
|
|
977
983
|
Show all available method of DataAnalystDataFrame
|
|
978
984
|
"""
|
|
@@ -981,7 +987,7 @@ class DataAnalystDataFrame(pd.DataFrame):
|
|
|
981
987
|
|
|
982
988
|
# Sample DataFrame
|
|
983
989
|
@classmethod
|
|
984
|
-
def sample_df(cls, size: int = 100):
|
|
990
|
+
def sample_df(cls, size: int = 100) -> Self:
|
|
985
991
|
"""
|
|
986
992
|
Create sample DataFrame
|
|
987
993
|
|
|
@@ -1057,6 +1063,46 @@ class DADF(DataAnalystDataFrame):
|
|
|
1057
1063
|
pass
|
|
1058
1064
|
|
|
1059
1065
|
|
|
1066
|
+
class DADF_WIP(DADF):
|
|
1067
|
+
"""W.I.P"""
|
|
1068
|
+
|
|
1069
|
+
@versionadded(version="4.0.0")
|
|
1070
|
+
def subtract_df(self, other: Self | pd.DataFrame) -> Self:
|
|
1071
|
+
"""
|
|
1072
|
+
Subtract DF to find the different rows
|
|
1073
|
+
"""
|
|
1074
|
+
temp = self.copy()
|
|
1075
|
+
out = (
|
|
1076
|
+
temp.merge(other, indicator=True, how="right")
|
|
1077
|
+
.query("_merge=='right_only'")
|
|
1078
|
+
.drop("_merge", axis=1)
|
|
1079
|
+
)
|
|
1080
|
+
return self.__class__(out)
|
|
1081
|
+
|
|
1082
|
+
@versionadded(version="4.0.0")
|
|
1083
|
+
def merge_left(
|
|
1084
|
+
self,
|
|
1085
|
+
other: Self | pd.DataFrame,
|
|
1086
|
+
on: str,
|
|
1087
|
+
columns: list[str] | None = None,
|
|
1088
|
+
) -> Self:
|
|
1089
|
+
"""
|
|
1090
|
+
Merge left of 2 dfs
|
|
1091
|
+
|
|
1092
|
+
:param columns: Columns to take from df2
|
|
1093
|
+
"""
|
|
1094
|
+
|
|
1095
|
+
if columns:
|
|
1096
|
+
current_col = [on]
|
|
1097
|
+
current_col.extend(columns)
|
|
1098
|
+
col = other.columns.to_list()
|
|
1099
|
+
cols = list(set(col) - set(current_col))
|
|
1100
|
+
self.drop_columns(cols)
|
|
1101
|
+
|
|
1102
|
+
out = self.merge(other, how="left", on=on)
|
|
1103
|
+
return self.__class__(out)
|
|
1104
|
+
|
|
1105
|
+
|
|
1060
1106
|
# Run
|
|
1061
1107
|
###########################################################################
|
|
1062
1108
|
if __name__ == "__main__":
|
|
@@ -3,8 +3,8 @@ Absfuyu: Fun
|
|
|
3
3
|
------------
|
|
4
4
|
Some fun or weird stuff
|
|
5
5
|
|
|
6
|
-
Version: 1.0.
|
|
7
|
-
Date updated:
|
|
6
|
+
Version: 1.0.7
|
|
7
|
+
Date updated: 16/08/2024 (dd/mm/yyyy)
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
# Library
|
|
@@ -24,7 +24,7 @@ def zodiac_sign(
|
|
|
24
24
|
day: int,
|
|
25
25
|
month: int,
|
|
26
26
|
zodiac13: bool = False,
|
|
27
|
-
):
|
|
27
|
+
) -> str:
|
|
28
28
|
"""
|
|
29
29
|
Calculate zodiac sign
|
|
30
30
|
|
|
@@ -43,9 +43,6 @@ def zodiac_sign(
|
|
|
43
43
|
-------
|
|
44
44
|
str
|
|
45
45
|
Zodiac sign
|
|
46
|
-
|
|
47
|
-
None
|
|
48
|
-
When failed
|
|
49
46
|
"""
|
|
50
47
|
|
|
51
48
|
# Condition check
|
|
@@ -57,34 +54,40 @@ def zodiac_sign(
|
|
|
57
54
|
raise ValueError("Value out of range")
|
|
58
55
|
|
|
59
56
|
zodiac = {
|
|
60
|
-
"Aquarius": any(
|
|
57
|
+
"Aquarius (A)": any(
|
|
61
58
|
[month == 1 and day >= 20, month == 2 and day <= 18]
|
|
62
59
|
), # 20/1-18/2
|
|
63
|
-
"Pisces": any(
|
|
60
|
+
"Pisces (W)": any(
|
|
64
61
|
[month == 2 and day >= 19, month == 3 and day <= 20]
|
|
65
62
|
), # 19/2-20/3
|
|
66
|
-
"Aries": any(
|
|
67
|
-
|
|
63
|
+
"Aries (F)": any(
|
|
64
|
+
[month == 3 and day >= 21, month == 4 and day <= 19]
|
|
65
|
+
), # 21/3-19/4
|
|
66
|
+
"Taurus (E)": any(
|
|
68
67
|
[month == 4 and day >= 20, month == 5 and day <= 20]
|
|
69
68
|
), # 20/4-20/5
|
|
70
|
-
"Gemini": any(
|
|
69
|
+
"Gemini (A)": any(
|
|
71
70
|
[month == 5 and day >= 21, month == 6 and day <= 20]
|
|
72
71
|
), # 21/5-20/6
|
|
73
|
-
"Cancer": any(
|
|
72
|
+
"Cancer (W)": any(
|
|
74
73
|
[month == 6 and day >= 21, month == 7 and day <= 22]
|
|
75
74
|
), # 21/6-22/7
|
|
76
|
-
"Leo": any(
|
|
77
|
-
|
|
78
|
-
|
|
75
|
+
"Leo (F)": any(
|
|
76
|
+
[month == 7 and day >= 23, month == 8 and day <= 22]
|
|
77
|
+
), # 23/7-22/8
|
|
78
|
+
"Virgo (E)": any(
|
|
79
|
+
[month == 8 and day >= 23, month == 9 and day <= 22]
|
|
80
|
+
), # 23/8-22/9
|
|
81
|
+
"Libra (A)": any(
|
|
79
82
|
[month == 9 and day >= 23, month == 10 and day <= 22]
|
|
80
83
|
), # 23/9-22/10
|
|
81
|
-
"Scorpio": any(
|
|
84
|
+
"Scorpio (W)": any(
|
|
82
85
|
[month == 10 and day >= 23, month == 11 and day <= 21]
|
|
83
86
|
), # 23/10-21/11
|
|
84
|
-
"Sagittarius": any(
|
|
87
|
+
"Sagittarius (F)": any(
|
|
85
88
|
[month == 11 and day >= 22, month == 12 and day <= 21]
|
|
86
89
|
), # 22/11-21/12
|
|
87
|
-
"Capricorn": any(
|
|
90
|
+
"Capricorn (E)": any(
|
|
88
91
|
[month == 12 and day >= 22, month == 1 and day <= 19]
|
|
89
92
|
), # 22/12-19/1
|
|
90
93
|
}
|
|
@@ -132,11 +135,9 @@ def zodiac_sign(
|
|
|
132
135
|
), # 21/1-16/2
|
|
133
136
|
}
|
|
134
137
|
|
|
135
|
-
logger.debug(zodiac)
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
if v is True:
|
|
139
|
-
return k
|
|
138
|
+
# logger.debug(zodiac)
|
|
139
|
+
temp = dict(zip(zodiac.values(), zodiac.keys()))
|
|
140
|
+
return temp[True]
|
|
140
141
|
|
|
141
142
|
|
|
142
143
|
def im_bored() -> str:
|