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.

Files changed (87) hide show
  1. {absfuyu-3.4.0 → absfuyu-4.0.0}/PKG-INFO +5 -9
  2. {absfuyu-3.4.0 → absfuyu-4.0.0}/pyproject.toml +15 -12
  3. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/__init__.py +1 -1
  4. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/cli/do_group.py +14 -2
  5. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/config/__init__.py +13 -13
  6. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/core.py +5 -16
  7. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/extensions/extra/data_analysis.py +74 -28
  8. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/fun/__init__.py +24 -23
  9. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/fun/tarot.py +6 -7
  10. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/game/__init__.py +1 -1
  11. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/game/sudoku.py +6 -5
  12. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/game/tictactoe.py +4 -4
  13. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/general/data_extension.py +41 -60
  14. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/pkg_data/__init__.py +13 -20
  15. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/tools/converter.py +9 -10
  16. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/util/__init__.py +13 -14
  17. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/util/api.py +7 -7
  18. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/util/json_method.py +9 -9
  19. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/util/lunar.py +7 -8
  20. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/util/path.py +23 -21
  21. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/util/performance.py +8 -8
  22. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/util/zipped.py +18 -6
  23. {absfuyu-3.4.0 → absfuyu-4.0.0}/tests/test_data_analysis.py +1 -0
  24. {absfuyu-3.4.0 → absfuyu-4.0.0}/tests/test_fun.py +3 -3
  25. {absfuyu-3.4.0 → absfuyu-4.0.0}/.gitignore +0 -0
  26. {absfuyu-3.4.0 → absfuyu-4.0.0}/LICENSE +0 -0
  27. {absfuyu-3.4.0 → absfuyu-4.0.0}/README.md +0 -0
  28. {absfuyu-3.4.0 → absfuyu-4.0.0}/dev_requirements.txt +0 -0
  29. {absfuyu-3.4.0 → absfuyu-4.0.0}/docs/Makefile +0 -0
  30. {absfuyu-3.4.0 → absfuyu-4.0.0}/docs/conf.py +0 -0
  31. {absfuyu-3.4.0 → absfuyu-4.0.0}/docs/index.rst +0 -0
  32. {absfuyu-3.4.0 → absfuyu-4.0.0}/docs/info.md +0 -0
  33. {absfuyu-3.4.0 → absfuyu-4.0.0}/docs/make.bat +0 -0
  34. {absfuyu-3.4.0 → absfuyu-4.0.0}/docs/modules.rst +0 -0
  35. {absfuyu-3.4.0 → absfuyu-4.0.0}/images/repository-image-crop.png +0 -0
  36. {absfuyu-3.4.0 → absfuyu-4.0.0}/images/repository-image-white.png +0 -0
  37. {absfuyu-3.4.0 → absfuyu-4.0.0}/images/repository-image.png +0 -0
  38. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/__main__.py +0 -0
  39. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/cli/__init__.py +0 -0
  40. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/cli/color.py +0 -0
  41. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/cli/config_group.py +0 -0
  42. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/cli/game_group.py +0 -0
  43. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/config/config.json +0 -0
  44. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/everything.py +0 -0
  45. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/extensions/__init__.py +0 -0
  46. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/extensions/beautiful.py +0 -0
  47. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/extensions/dev/__init__.py +0 -0
  48. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/extensions/dev/password_hash.py +0 -0
  49. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/extensions/dev/passwordlib.py +0 -0
  50. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/extensions/dev/project_starter.py +0 -0
  51. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/extensions/dev/shutdownizer.py +0 -0
  52. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/extensions/extra/__init__.py +0 -0
  53. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/fun/WGS.py +0 -0
  54. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/game/game_stat.py +0 -0
  55. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/game/wordle.py +0 -0
  56. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/general/__init__.py +0 -0
  57. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/general/content.py +0 -0
  58. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/general/generator.py +0 -0
  59. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/general/human.py +0 -0
  60. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/logger.py +0 -0
  61. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/pkg_data/chemistry.pkl +0 -0
  62. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/pkg_data/tarot.pkl +0 -0
  63. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/py.typed +0 -0
  64. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/sort.py +0 -0
  65. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/tools/__init__.py +0 -0
  66. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/tools/keygen.py +0 -0
  67. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/tools/obfuscator.py +0 -0
  68. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/tools/stats.py +0 -0
  69. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/tools/web.py +0 -0
  70. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/util/pkl.py +0 -0
  71. {absfuyu-3.4.0 → absfuyu-4.0.0}/src/absfuyu/version.py +0 -0
  72. {absfuyu-3.4.0 → absfuyu-4.0.0}/tests/__init__.py +0 -0
  73. {absfuyu-3.4.0 → absfuyu-4.0.0}/tests/conftest.py +0 -0
  74. {absfuyu-3.4.0 → absfuyu-4.0.0}/tests/test_beautiful.py +0 -0
  75. {absfuyu-3.4.0 → absfuyu-4.0.0}/tests/test_config.py +0 -0
  76. {absfuyu-3.4.0 → absfuyu-4.0.0}/tests/test_data_extension.py +0 -0
  77. {absfuyu-3.4.0 → absfuyu-4.0.0}/tests/test_everything.py +0 -0
  78. {absfuyu-3.4.0 → absfuyu-4.0.0}/tests/test_extensions.py +0 -0
  79. {absfuyu-3.4.0 → absfuyu-4.0.0}/tests/test_game.py +0 -0
  80. {absfuyu-3.4.0 → absfuyu-4.0.0}/tests/test_generator.py +0 -0
  81. {absfuyu-3.4.0 → absfuyu-4.0.0}/tests/test_logger.py +0 -0
  82. {absfuyu-3.4.0 → absfuyu-4.0.0}/tests/test_passwordlib.py +0 -0
  83. {absfuyu-3.4.0 → absfuyu-4.0.0}/tests/test_pkg_data.py +0 -0
  84. {absfuyu-3.4.0 → absfuyu-4.0.0}/tests/test_tarot.py +0 -0
  85. {absfuyu-3.4.0 → absfuyu-4.0.0}/tests/test_tools.py +0 -0
  86. {absfuyu-3.4.0 → absfuyu-4.0.0}/tests/test_util.py +0 -0
  87. {absfuyu-3.4.0 → absfuyu-4.0.0}/tests/test_version.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: absfuyu
3
- Version: 3.4.0
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.8
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: tomli>=1.1.0; python_version < '3.11'
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.8, <4"
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
- "tomli>=1.1.0; python_version < '3.11'",
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.8", "3.9", "3.10", "3.11", "3.12"]
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 = "py38"
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" = ["E741"] # Ambiguous variable name
272
- "test_everything.py" = ["F403"] # unable to detect undefined names
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/*" = ["F401"] # imported but unused
279
+ "tests/*" = [
280
+ "F401", # imported but unused
281
+ ]
279
282
 
280
283
  # MARK: TOOL: black
281
284
  [tool.black]
@@ -22,7 +22,7 @@ Using in cmd (`absfuyu[cli]` required):
22
22
  __title__ = "absfuyu"
23
23
  __author__ = "AbsoluteWinter"
24
24
  __license__ = "MIT License"
25
- __version__ = "3.4.0"
25
+ __version__ = "4.0.0"
26
26
  __all__ = [
27
27
  "core",
28
28
  "config",
@@ -3,8 +3,8 @@ ABSFUYU CLI
3
3
  -----------
4
4
  Do
5
5
 
6
- Version: 1.1.0
7
- Date updated: 15/08/2024 (dd/mm/yyyy)
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.4
7
- Date updated: 06/04/2024 (dd/mm/yyyy)
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, Dict, List, Optional, TypedDict
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: Dict[str, SettingDictFormat]
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: Dict[str, SettingDictFormat]):
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) -> Dict[str, SettingDictFormat]:
107
+ def to_dict(self) -> dict[str, SettingDictFormat]:
108
108
  """
109
109
  Convert ``Setting`` into ``dict``
110
110
  """
111
- output: Dict[str, SettingDictFormat] = {
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: Optional[str] = None) -> None:
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: List[Setting] = None # type: ignore
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: Dict[str, SettingDictFormat] = data.get("setting") # type: ignore
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) -> List[str]:
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) -> List[Setting]:
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.0
7
- Date updated: 14/04/2024 (dd/mm/yyyy)
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 pathlib import Path
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
- # CORE_PATH = files("absfuyu")
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.1.3
7
- Date updated: 20/03/2024 (dd/mm/yyyy)
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, Dict, List, NamedTuple, Optional, Union
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: Union[list, np.ndarray]): # del this
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: Dict[str, list], fillna=np.nan) -> Dict[str, list]:
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) -> List["CityData"]:
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: List[str] = []
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(df_list: List[pd.DataFrame], join: str = "inner"):
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: str = "inner"):
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) -> List[pd.DataFrame]:
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() -> List[PLTFormatString]:
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: List[str]):
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: List[CityData],
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, date_column: str, mode: str = "now", *, col_name: str = "delta_date"
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: ``"between_row"``)
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: Union[int, float] = 10,
780
+ threshold: int | float = 10,
775
781
  *,
776
- top: Optional[int] = None,
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() -> List[str]:
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.6
7
- Date updated: 05/04/2023 (dd/mm/yyyy)
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([month == 3 and day >= 21, month == 4 and day <= 19]), # 21/3-19/4
67
- "Taurus": any(
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([month == 7 and day >= 23, month == 8 and day <= 22]), # 23/7-22/8
77
- "Virgo": any([month == 8 and day >= 23, month == 9 and day <= 22]), # 23/8-22/9
78
- "Libra": any(
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
- for k, v in zodiac.items():
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: