absfuyu 5.6.1__tar.gz → 5.7.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 (123) hide show
  1. {absfuyu-5.6.1 → absfuyu-5.7.0}/PKG-INFO +5 -4
  2. {absfuyu-5.6.1 → absfuyu-5.7.0}/pyproject.toml +33 -10
  3. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/__init__.py +1 -1
  4. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/__main__.py +1 -1
  5. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/cli/__init__.py +1 -1
  6. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/cli/color.py +1 -1
  7. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/cli/config_group.py +1 -1
  8. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/cli/do_group.py +1 -1
  9. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/cli/game_group.py +1 -1
  10. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/cli/tool_group.py +1 -1
  11. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/config/__init__.py +1 -1
  12. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/core/__init__.py +1 -1
  13. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/core/baseclass.py +1 -1
  14. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/core/baseclass2.py +1 -1
  15. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/core/decorator.py +1 -1
  16. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/core/docstring.py +1 -1
  17. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/core/dummy_cli.py +1 -1
  18. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/core/dummy_func.py +1 -1
  19. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/dxt/__init__.py +1 -1
  20. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/dxt/dictext.py +1 -1
  21. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/dxt/dxt_support.py +1 -1
  22. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/dxt/intext.py +1 -1
  23. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/dxt/listext.py +1 -1
  24. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/dxt/strext.py +1 -1
  25. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/extra/__init__.py +1 -1
  26. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/extra/beautiful.py +1 -1
  27. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/extra/da/__init__.py +4 -2
  28. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/extra/da/dadf.py +109 -11
  29. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/extra/da/dadf_base.py +1 -1
  30. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/extra/da/df_func.py +1 -1
  31. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/extra/da/mplt.py +1 -1
  32. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/extra/data_analysis.py +1 -1
  33. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/extra/pdf.py +2 -4
  34. absfuyu-5.7.0/src/absfuyu/extra/xml.py +90 -0
  35. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/fun/__init__.py +1 -1
  36. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/fun/rubik.py +1 -1
  37. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/fun/tarot.py +1 -1
  38. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/game/__init__.py +1 -1
  39. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/game/game_stat.py +1 -1
  40. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/game/sudoku.py +1 -1
  41. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/game/tictactoe.py +1 -1
  42. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/game/wordle.py +1 -1
  43. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/general/__init__.py +1 -1
  44. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/general/content.py +1 -1
  45. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/general/human.py +1 -1
  46. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/general/shape.py +1 -1
  47. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/logger.py +1 -1
  48. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/pkg_data/__init__.py +1 -1
  49. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/pkg_data/deprecated.py +1 -1
  50. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/sort.py +1 -1
  51. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/tools/__init__.py +1 -1
  52. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/tools/checksum.py +1 -1
  53. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/tools/converter.py +1 -1
  54. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/tools/generator.py +1 -1
  55. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/tools/inspector.py +1 -1
  56. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/tools/keygen.py +1 -1
  57. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/tools/obfuscator.py +1 -1
  58. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/tools/passwordlib.py +1 -1
  59. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/tools/shutdownizer.py +1 -1
  60. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/tools/sw.py +1 -1
  61. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/tools/web.py +1 -1
  62. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/typings.py +1 -1
  63. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/util/__init__.py +1 -1
  64. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/util/api.py +1 -1
  65. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/util/json_method.py +1 -1
  66. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/util/lunar.py +1 -1
  67. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/util/path.py +1 -1
  68. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/util/performance.py +1 -1
  69. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/util/shorten_number.py +1 -1
  70. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/util/text_table.py +1 -1
  71. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/util/zipped.py +1 -1
  72. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/version.py +1 -1
  73. {absfuyu-5.6.1 → absfuyu-5.7.0}/tests/conftest.py +1 -1
  74. {absfuyu-5.6.1 → absfuyu-5.7.0}/tests/test_api.py +1 -1
  75. {absfuyu-5.6.1 → absfuyu-5.7.0}/tests/test_beautiful.py +1 -1
  76. {absfuyu-5.6.1 → absfuyu-5.7.0}/tests/test_config.py +1 -1
  77. {absfuyu-5.6.1 → absfuyu-5.7.0}/tests/test_converter.py +1 -1
  78. {absfuyu-5.6.1 → absfuyu-5.7.0}/tests/test_core.py +1 -1
  79. {absfuyu-5.6.1 → absfuyu-5.7.0}/tests/test_data_analysis.py +1 -1
  80. {absfuyu-5.6.1 → absfuyu-5.7.0}/tests/test_dictext.py +1 -1
  81. {absfuyu-5.6.1 → absfuyu-5.7.0}/tests/test_everything.py +1 -1
  82. {absfuyu-5.6.1 → absfuyu-5.7.0}/tests/test_extra.py +1 -1
  83. {absfuyu-5.6.1 → absfuyu-5.7.0}/tests/test_fun.py +1 -1
  84. {absfuyu-5.6.1 → absfuyu-5.7.0}/tests/test_game.py +1 -1
  85. {absfuyu-5.6.1 → absfuyu-5.7.0}/tests/test_generator.py +1 -1
  86. {absfuyu-5.6.1 → absfuyu-5.7.0}/tests/test_inspector.py +1 -1
  87. {absfuyu-5.6.1 → absfuyu-5.7.0}/tests/test_intext.py +1 -1
  88. {absfuyu-5.6.1 → absfuyu-5.7.0}/tests/test_listext.py +1 -1
  89. {absfuyu-5.6.1 → absfuyu-5.7.0}/tests/test_logger.py +1 -1
  90. {absfuyu-5.6.1 → absfuyu-5.7.0}/tests/test_obfuscator.py +1 -1
  91. {absfuyu-5.6.1 → absfuyu-5.7.0}/tests/test_passwordlib.py +1 -1
  92. {absfuyu-5.6.1 → absfuyu-5.7.0}/tests/test_performance.py +1 -1
  93. {absfuyu-5.6.1 → absfuyu-5.7.0}/tests/test_pkg_data.py +1 -1
  94. {absfuyu-5.6.1 → absfuyu-5.7.0}/tests/test_shape.py +1 -1
  95. {absfuyu-5.6.1 → absfuyu-5.7.0}/tests/test_shorten_number.py +1 -1
  96. {absfuyu-5.6.1 → absfuyu-5.7.0}/tests/test_strext.py +1 -1
  97. {absfuyu-5.6.1 → absfuyu-5.7.0}/tests/test_text_table.py +1 -1
  98. {absfuyu-5.6.1 → absfuyu-5.7.0}/tests/test_tools.py +1 -1
  99. {absfuyu-5.6.1 → absfuyu-5.7.0}/tests/test_util.py +1 -1
  100. {absfuyu-5.6.1 → absfuyu-5.7.0}/tests/test_version.py +1 -1
  101. {absfuyu-5.6.1 → absfuyu-5.7.0}/.gitignore +0 -0
  102. {absfuyu-5.6.1 → absfuyu-5.7.0}/LICENSE +0 -0
  103. {absfuyu-5.6.1 → absfuyu-5.7.0}/README.md +0 -0
  104. {absfuyu-5.6.1 → absfuyu-5.7.0}/dev_requirements.txt +0 -0
  105. {absfuyu-5.6.1 → absfuyu-5.7.0}/docs/Makefile +0 -0
  106. {absfuyu-5.6.1 → absfuyu-5.7.0}/docs/_template/versioning.html +0 -0
  107. {absfuyu-5.6.1 → absfuyu-5.7.0}/docs/conf.py +0 -0
  108. {absfuyu-5.6.1 → absfuyu-5.7.0}/docs/index.rst +0 -0
  109. {absfuyu-5.6.1 → absfuyu-5.7.0}/docs/info.md +0 -0
  110. {absfuyu-5.6.1 → absfuyu-5.7.0}/docs/make.bat +0 -0
  111. {absfuyu-5.6.1 → absfuyu-5.7.0}/docs/modules.rst +0 -0
  112. {absfuyu-5.6.1 → absfuyu-5.7.0}/images/Logo Full.png +0 -0
  113. {absfuyu-5.6.1 → absfuyu-5.7.0}/images/Logo Square.png +0 -0
  114. {absfuyu-5.6.1 → absfuyu-5.7.0}/images/Logo White.png +0 -0
  115. {absfuyu-5.6.1 → absfuyu-5.7.0}/images/repository-image-crop.png +0 -0
  116. {absfuyu-5.6.1 → absfuyu-5.7.0}/images/repository-image-white.png +0 -0
  117. {absfuyu-5.6.1 → absfuyu-5.7.0}/images/repository-image.png +0 -0
  118. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/config/config.json +0 -0
  119. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/pkg_data/chemistry.pkl +0 -0
  120. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/pkg_data/passwordlib_lzma.pkl +0 -0
  121. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/pkg_data/tarot.pkl +0 -0
  122. {absfuyu-5.6.1 → absfuyu-5.7.0}/src/absfuyu/py.typed +0 -0
  123. {absfuyu-5.6.1 → absfuyu-5.7.0}/tests/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: absfuyu
3
- Version: 5.6.1
3
+ Version: 5.7.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/
@@ -31,9 +31,6 @@ Requires-Dist: colorama
31
31
  Requires-Dist: requests
32
32
  Provides-Extra: beautiful
33
33
  Requires-Dist: rich; extra == 'beautiful'
34
- Provides-Extra: dev
35
- Requires-Dist: hatch; extra == 'dev'
36
- Requires-Dist: pytest; extra == 'dev'
37
34
  Provides-Extra: docs
38
35
  Requires-Dist: numpy; extra == 'docs'
39
36
  Requires-Dist: pandas; extra == 'docs'
@@ -44,6 +41,8 @@ Requires-Dist: numpy; extra == 'extra'
44
41
  Requires-Dist: openpyxl; extra == 'extra'
45
42
  Requires-Dist: pandas; extra == 'extra'
46
43
  Requires-Dist: spire-pdf; extra == 'extra'
44
+ Requires-Dist: xlsxwriter; extra == 'extra'
45
+ Requires-Dist: xmltodict; extra == 'extra'
47
46
  Provides-Extra: full
48
47
  Requires-Dist: numpy; extra == 'full'
49
48
  Requires-Dist: openpyxl; extra == 'full'
@@ -52,6 +51,8 @@ Requires-Dist: rich; extra == 'full'
52
51
  Requires-Dist: spire-pdf; extra == 'full'
53
52
  Requires-Dist: tqdm; extra == 'full'
54
53
  Requires-Dist: unidecode; extra == 'full'
54
+ Requires-Dist: xlsxwriter; extra == 'full'
55
+ Requires-Dist: xmltodict; extra == 'full'
55
56
  Description-Content-Type: text/markdown
56
57
 
57
58
  <div align="center">
@@ -58,13 +58,21 @@ Issues = "https://github.com/AbsoluteWinter/absfuyu-public/issues"
58
58
 
59
59
  [project.optional-dependencies]
60
60
  full = [
61
- "numpy", "pandas", "rich", "tqdm", "unidecode", "openpyxl", "spire-pdf",
61
+ "numpy",
62
+ "pandas",
63
+ "rich",
64
+ "tqdm",
65
+ "unidecode",
66
+ "openpyxl",
67
+ "xlsxwriter",
68
+ "spire-pdf",
69
+ "xmltodict",
62
70
  # "jinja2"
63
71
  ]
64
72
  docs = ["numpy", "pandas", "rich", "spire-pdf"]
65
73
  beautiful = ["rich"]
66
- extra = ["numpy", "pandas", "openpyxl", "spire-pdf"]
67
- dev = ["hatch", "pytest"]
74
+ extra = ["numpy", "pandas", "openpyxl", "xlsxwriter", "spire-pdf", "xmltodict"]
75
+
68
76
 
69
77
  [project.scripts]
70
78
  absfuyu = "absfuyu.__main__:main"
@@ -98,7 +106,13 @@ cov = ["test-cov", "cov-report"] # use this
98
106
  cov2 = "pytest --cov-report=term-missing --cov=absfuyu --cov=tests" # use this
99
107
 
100
108
  [tool.hatch.envs.all]
101
- dependencies = ["coverage[toml]", "pytest", "pytest-cov", "pytest-mock", "pytest-xdist"]
109
+ dependencies = [
110
+ "coverage[toml]",
111
+ "pytest",
112
+ "pytest-cov",
113
+ "pytest-mock",
114
+ "pytest-xdist",
115
+ ]
102
116
  features = ["full"]
103
117
  description = """
104
118
  All python version to test:
@@ -157,7 +171,7 @@ clean = [
157
171
  """,
158
172
  ]
159
173
  build_only = [
160
- "sphinx-build docs docs/build", # Build
174
+ "sphinx-build docs docs/build", # Build
161
175
  ]
162
176
  build_private = [
163
177
  # -f --force
@@ -215,7 +229,7 @@ qa = [
215
229
  ]
216
230
  test = [
217
231
  "qa",
218
- "hatch run all:test", # Test
232
+ "hatch run all:test", # Test
219
233
  ]
220
234
  build = [
221
235
  # Update license year - Convert to hex due to unable to run multiple lines
@@ -244,8 +258,8 @@ build = [
244
258
  9617320663a662e77726974656c696e65732863290a7072696e7428224c6963656e7365\
245
259
  207965617220757064617465642229').decode('utf-8'))\"
246
260
  """,
247
- "hatch clean", # Clean dist/ folder
248
- "hatch -v build", # Build package
261
+ "hatch clean", # Clean dist/ folder
262
+ "hatch -v build", # Build package
249
263
  "hatch run docs:build", # Build docs
250
264
  ]
251
265
  patch = [
@@ -307,7 +321,7 @@ no_implicit_reexport = true
307
321
 
308
322
  # MARK: TOOL: ruff
309
323
  [tool.ruff]
310
- line-length = 88
324
+ line-length = 120
311
325
  indent-width = 4
312
326
  target-version = "py311"
313
327
  include = ["pyproject.toml", "src/**", "tests/**"]
@@ -353,4 +367,13 @@ convention = "numpy"
353
367
 
354
368
  # MARK: TOOL: black
355
369
  [tool.black]
356
- line-length = 88
370
+ line-length = 120
371
+
372
+ # MARK: TOOL: uv
373
+ [tool.uv]
374
+ required-version = ">=0.5.0"
375
+ cache-dir = "./.uv_cache"
376
+ dev-dependencies = ["ruff", "mypy>=1.18.0", "pytest>=8.4.0", "hatch>=1.14.1"]
377
+
378
+ [tool.uv.build-backend]
379
+ source-include = ["tests/**"]
@@ -22,7 +22,7 @@ Using in cmd:
22
22
  __title__ = "absfuyu"
23
23
  __author__ = "AbsoluteWinter"
24
24
  __license__ = "MIT License"
25
- __version__ = "5.6.1"
25
+ __version__ = "5.7.0"
26
26
  __all__ = [
27
27
  "core",
28
28
  "config",
@@ -3,7 +3,7 @@ ABSFUYU
3
3
  -------
4
4
  COMMAND LINE INTERFACE
5
5
 
6
- Version: 5.6.1
6
+ Version: 5.7.0
7
7
  Date updated: 12/09/2025 (dd/mm/yyyy)
8
8
  """
9
9
 
@@ -3,7 +3,7 @@ ABSFUYU
3
3
  -------
4
4
  COMMAND LINE INTERFACE
5
5
 
6
- Version: 5.6.1
6
+ Version: 5.7.0
7
7
  Date updated: 12/09/2025 (dd/mm/yyyy)
8
8
  """
9
9
 
@@ -3,7 +3,7 @@ ABSFUYU CLI
3
3
  -----------
4
4
  Color
5
5
 
6
- Version: 5.6.1
6
+ Version: 5.7.0
7
7
  Date updated: 12/09/2025 (dd/mm/yyyy)
8
8
  """
9
9
 
@@ -3,7 +3,7 @@ ABSFUYU CLI
3
3
  -----------
4
4
  Config
5
5
 
6
- Version: 5.6.1
6
+ Version: 5.7.0
7
7
  Date updated: 12/09/2025 (dd/mm/yyyy)
8
8
  """
9
9
 
@@ -3,7 +3,7 @@ ABSFUYU CLI
3
3
  -----------
4
4
  Do
5
5
 
6
- Version: 5.6.1
6
+ Version: 5.7.0
7
7
  Date updated: 12/09/2025 (dd/mm/yyyy)
8
8
  """
9
9
 
@@ -3,7 +3,7 @@ ABSFUYU CLI
3
3
  -----------
4
4
  Game
5
5
 
6
- Version: 5.6.1
6
+ Version: 5.7.0
7
7
  Date updated: 12/09/2025 (dd/mm/yyyy)
8
8
  """
9
9
 
@@ -3,7 +3,7 @@ ABSFUYU CLI
3
3
  -----------
4
4
  Tool
5
5
 
6
- Version: 5.6.1
6
+ Version: 5.7.0
7
7
  Date updated: 12/09/2025 (dd/mm/yyyy)
8
8
  """
9
9
 
@@ -3,7 +3,7 @@ Absfuyu: Configuration
3
3
  ----------------------
4
4
  Package configuration module
5
5
 
6
- Version: 5.6.1
6
+ Version: 5.7.0
7
7
  Date updated: 12/09/2025 (dd/mm/yyyy)
8
8
  """
9
9
 
@@ -3,7 +3,7 @@ Absfuyu: Core
3
3
  -------------
4
4
  Bases for other features
5
5
 
6
- Version: 5.6.1
6
+ Version: 5.7.0
7
7
  Date updated: 12/09/2025 (dd/mm/yyyy)
8
8
  """
9
9
 
@@ -3,7 +3,7 @@ Absfuyu: Core
3
3
  -------------
4
4
  Bases for other features
5
5
 
6
- Version: 5.6.1
6
+ Version: 5.7.0
7
7
  Date updated: 12/09/2025 (dd/mm/yyyy)
8
8
  """
9
9
 
@@ -3,7 +3,7 @@ Absfuyu: Core
3
3
  -------------
4
4
  Bases for other features (with library)
5
5
 
6
- Version: 5.6.1
6
+ Version: 5.7.0
7
7
  Date updated: 12/09/2025 (dd/mm/yyyy)
8
8
  """
9
9
 
@@ -3,7 +3,7 @@ Absfuyu: Core
3
3
  -------------
4
4
  Decorator
5
5
 
6
- Version: 5.6.1
6
+ Version: 5.7.0
7
7
  Date updated: 12/09/2025 (dd/mm/yyyy)
8
8
  """
9
9
 
@@ -3,7 +3,7 @@ Absfuyu: Core
3
3
  -------------
4
4
  Sphinx docstring decorator
5
5
 
6
- Version: 5.6.1
6
+ Version: 5.7.0
7
7
  Date updated: 12/09/2025 (dd/mm/yyyy)
8
8
  """
9
9
 
@@ -3,7 +3,7 @@ Absfuyu: Core
3
3
  -------------
4
4
  Dummy cli
5
5
 
6
- Version: 5.6.1
6
+ Version: 5.7.0
7
7
  Date updated: 12/09/2025 (dd/mm/yyyy)
8
8
  """
9
9
 
@@ -3,7 +3,7 @@ Absfuyu: Core
3
3
  -------------
4
4
  Dummy functions when other libraries are unvailable
5
5
 
6
- Version: 5.6.1
6
+ Version: 5.7.0
7
7
  Date updated: 12/09/2025 (dd/mm/yyyy)
8
8
  """
9
9
 
@@ -3,7 +3,7 @@ Absfuyu: Data Extension
3
3
  -----------------------
4
4
  Extension for data type such as ``list``, ``str``, ``dict``, ...
5
5
 
6
- Version: 5.6.1
6
+ Version: 5.7.0
7
7
  Date updated: 12/09/2025 (dd/mm/yyyy)
8
8
 
9
9
  Features:
@@ -3,7 +3,7 @@ Absfuyu: Data Extension
3
3
  -----------------------
4
4
  dict extension
5
5
 
6
- Version: 5.6.1
6
+ Version: 5.7.0
7
7
  Date updated: 12/09/2025 (dd/mm/yyyy)
8
8
  """
9
9
 
@@ -3,7 +3,7 @@ Absfuyu: Data Extension
3
3
  -----------------------
4
4
  Support classes
5
5
 
6
- Version: 5.6.1
6
+ Version: 5.7.0
7
7
  Date updated: 12/09/2025 (dd/mm/yyyy)
8
8
  """
9
9
 
@@ -3,7 +3,7 @@ Absfuyu: Data Extension
3
3
  -----------------------
4
4
  int extension
5
5
 
6
- Version: 5.6.1
6
+ Version: 5.7.0
7
7
  Date updated: 12/09/2025 (dd/mm/yyyy)
8
8
  """
9
9
 
@@ -3,7 +3,7 @@ Absfuyu: Data Extension
3
3
  -----------------------
4
4
  list extension
5
5
 
6
- Version: 5.6.1
6
+ Version: 5.7.0
7
7
  Date updated: 12/09/2025 (dd/mm/yyyy)
8
8
  """
9
9
 
@@ -3,7 +3,7 @@ Absfuyu: Data Extension
3
3
  -----------------------
4
4
  str extension
5
5
 
6
- Version: 5.6.1
6
+ Version: 5.7.0
7
7
  Date updated: 12/09/2025 (dd/mm/yyyy)
8
8
  """
9
9
 
@@ -3,7 +3,7 @@ Absfuyu: Extra
3
3
  --------------
4
4
  Features that require additional libraries
5
5
 
6
- Version: 5.6.1
6
+ Version: 5.7.0
7
7
  Date updated: 12/09/2025 (dd/mm/yyyy)
8
8
  """
9
9
 
@@ -3,7 +3,7 @@ Absfuyu: Beautiful
3
3
  ------------------
4
4
  A decorator that makes output more beautiful
5
5
 
6
- Version: 5.6.1
6
+ Version: 5.7.0
7
7
  Date updated: 12/09/2025 (dd/mm/yyyy)
8
8
  """
9
9
 
@@ -3,8 +3,8 @@ Absfuyu: Data Analysis
3
3
  ----------------------
4
4
  Data Analyst
5
5
 
6
- Version: 5.6.1
7
- Date updated: 12/09/2025 (dd/mm/yyyy)
6
+ Version: 5.7.0
7
+ Date updated: 16/09/2025 (dd/mm/yyyy)
8
8
  """
9
9
 
10
10
  # Module level
@@ -18,7 +18,9 @@ DA_MODE = False
18
18
 
19
19
  try:
20
20
  import numpy as np
21
+ import openpyxl
21
22
  import pandas as pd
23
+ import xlsxwriter
22
24
  except ImportError:
23
25
  from subprocess import run
24
26
 
@@ -3,8 +3,8 @@ Absfuyu: Data Analysis
3
3
  ----------------------
4
4
  Data Analyst DataFrame
5
5
 
6
- Version: 5.6.1
7
- Date updated: 12/09/2025 (dd/mm/yyyy)
6
+ Version: 5.7.0
7
+ Date updated: 16/09/2025 (dd/mm/yyyy)
8
8
  """
9
9
 
10
10
  # Module level
@@ -17,6 +17,7 @@ __all__ = [
17
17
  "DataAnalystDataFrameNAMixin",
18
18
  "DataAnalystDataFrameOtherMixin",
19
19
  "DataAnalystDataFrameDateMixin",
20
+ "DataAnalystDataFrameExportMixin",
20
21
  "DataAnalystDataFrameCityMixin",
21
22
  ]
22
23
 
@@ -31,6 +32,8 @@ from typing import Any, Literal, Self
31
32
 
32
33
  import numpy as np
33
34
  import pandas as pd
35
+ from xlsxwriter import Workbook
36
+ from xlsxwriter.worksheet import Worksheet
34
37
 
35
38
  try:
36
39
  from typing import override # type: ignore
@@ -183,7 +186,9 @@ class DataAnalystDataFrameColumnMethodMixin(DFBase):
183
186
  @deprecated("5.1.0", reason="Use pd.DataFrame.assign(...) method instead")
184
187
  def add_blank_column(self, column_name: str, fill: Any = np.nan, /) -> Self:
185
188
  """
186
- Add a blank column
189
+ [DEPRECATED] Add a blank column.
190
+
191
+ E.g: Use `pd.DataFrame.assign(new_col=lambda x: x['old_col'])` instead
187
192
 
188
193
  Parameters
189
194
  ----------
@@ -246,9 +251,7 @@ class DataAnalystDataFrameColumnMethodMixin(DFBase):
246
251
  """
247
252
  if n is None:
248
253
  pass
249
- splited_data: pd.DataFrame = self[col].str.split(
250
- pat=pattern, n=n, expand=True, regex=regex
251
- )
254
+ splited_data: pd.DataFrame = self[col].str.split(pat=pattern, n=n, expand=True, regex=regex) # type: ignore
252
255
  num_of_splitted_cols = splited_data.shape[1]
253
256
  new_col_names = [f"{col}_{x}" for x in range(num_of_splitted_cols)]
254
257
  self[new_col_names] = splited_data
@@ -262,6 +265,7 @@ class DataAnalystDataFrameRowMethodMixin(DFBase):
262
265
  Data Analyst ``pd.DataFrame`` - Row method
263
266
 
264
267
  - Get different rows
268
+ - Add blank row
265
269
  """
266
270
 
267
271
  @versionadded("4.0.0")
@@ -297,6 +301,26 @@ class DataAnalystDataFrameRowMethodMixin(DFBase):
297
301
  )
298
302
  return self.__class__(out)
299
303
 
304
+ @versionadded("5.7.0")
305
+ def add_blank_row(self, fill: Any = np.nan, /) -> Self:
306
+ """
307
+ Add a new row to the end of a DataFrame.
308
+
309
+ Parameters
310
+ ----------
311
+ fill : Any, default np.nan
312
+ Value to fill in the new row (e.g., np.nan, None, "", 0).
313
+
314
+ Returns
315
+ -------
316
+ Self
317
+ DataFrame with the new row appended.
318
+ """
319
+ # Create a dict with all columns filled with fill
320
+ new_row = {col: fill for col in self.columns}
321
+ self.loc[len(self)] = new_row # type: ignore
322
+ return self
323
+
300
324
 
301
325
  # Info
302
326
  # ---------------------------------------------------------------------------
@@ -486,7 +510,7 @@ class DataAnalystDataFrameInfoMixin(DFBase):
486
510
  if top is not None:
487
511
  list_of_keep: list = (
488
512
  col_df[destination_column]
489
- .head(set_min_max(top - 1, min_value=1, max_value=col_df.shape[0]))
513
+ .head(set_min_max(top - 1, min_value=1, max_value=col_df.shape[0])) # type: ignore
490
514
  .to_list()
491
515
  )
492
516
  # logger.debug(list_of_keep)
@@ -561,7 +585,7 @@ class DataAnalystDataFrameNAMixin(DFBase):
561
585
  except KeyError:
562
586
  if getattr(self, "add_blank_column", None) is not None:
563
587
  # Compatible with DataAnalystDataFrameColumnMethodMixin
564
- self.add_blank_column(column_name, fill_when_not_exist)
588
+ self.add_blank_column(column_name, fill_when_not_exist) # type: ignore
565
589
  return self
566
590
 
567
591
  def get_missing_values(
@@ -679,7 +703,7 @@ class DataAnalystDataFrameNAMixin(DFBase):
679
703
  3 -1.435079 400 400 REPLACED ywahcasi 2024-05-20
680
704
  4 0.118993 861 800 REPLACED saoupuby 2019-04-28
681
705
  """
682
- self[col] = self[col].apply(lambda x: callable(x) if pd.notnull(x) else x)
706
+ self[col] = self[col].apply(lambda x: callable(x) if pd.notnull(x) else x) # type: ignore
683
707
  return self
684
708
 
685
709
  @versionadded("5.1.0") # type: ignore
@@ -750,7 +774,7 @@ class DataAnalystDataFrameNAMixin(DFBase):
750
774
 
751
775
  # Column name
752
776
  cname = "applied_row_null" if col_name is None else col_name
753
- self[cname] = self.apply(apply_func, axis=1)
777
+ self[cname] = self.apply(apply_func, axis=1) # type: ignore
754
778
 
755
779
  return self
756
780
 
@@ -825,7 +849,7 @@ class DataAnalystDataFrameOtherMixin(DFBase):
825
849
 
826
850
  if getattr(self, "drop_columns", None) is not None:
827
851
  # Compatible with DataAnalystDataFrameColumnMethodMixin
828
- self.drop_columns(cols)
852
+ self.drop_columns(cols) # type: ignore
829
853
 
830
854
  out = self.merge(other, how="left", on=on)
831
855
  return self.__class__(out)
@@ -1018,6 +1042,79 @@ class DataAnalystDataFrameDateMixin(DFBase):
1018
1042
  return self
1019
1043
 
1020
1044
 
1045
+ # Export
1046
+ # ---------------------------------------------------------------------------
1047
+ class DataAnalystDataFrameExportMixin(DFBase):
1048
+ """
1049
+ Data Analyst ``pd.DataFrame`` - Export method
1050
+
1051
+ - da_export
1052
+ """
1053
+
1054
+ def da_export(self, path: str, sheet_name: str = "Sheet1", cols_contain_number: list[str] | None = None) -> None:
1055
+ """
1056
+ Export DataFrame with `xlsxwriter` engine
1057
+
1058
+ Parameters
1059
+ ----------
1060
+ path : Path | str
1061
+ Path to export
1062
+
1063
+ sheet_name : str
1064
+ Sheet name
1065
+
1066
+ cols_contain_number : list[str]
1067
+ Columns that contain number value (to format as number)
1068
+ """
1069
+ # Using xlsxwriter engine
1070
+ with pd.ExcelWriter(path, engine="xlsxwriter") as writer:
1071
+ self.to_excel(writer, sheet_name=sheet_name, index=False, float_format="%.2f", na_rep="")
1072
+
1073
+ # Format style
1074
+ workbook: Workbook = writer.book # type: ignore
1075
+ header_fmt = workbook.add_format(
1076
+ {
1077
+ "bold": True,
1078
+ "text_wrap": True,
1079
+ "border": 1,
1080
+ "align": "center",
1081
+ "valign": "vcenter",
1082
+ # "bg_color": "#A0BEFD",
1083
+ }
1084
+ )
1085
+ number_fmt = workbook.add_format(
1086
+ {
1087
+ "num_format": "#,##0",
1088
+ "align": "center",
1089
+ "valign": "vcenter",
1090
+ }
1091
+ ) # 1,000,000
1092
+ text_fmt = workbook.add_format({"valign": "vcenter"})
1093
+ text_center_fmt = workbook.add_format({"align": "center", "valign": "vcenter"})
1094
+
1095
+ # Format sheet
1096
+ worksheet: Worksheet = writer.sheets[sheet_name]
1097
+
1098
+ # Format header - First row
1099
+ for col_num, value in enumerate(self.columns.values):
1100
+ worksheet.write(0, col_num, value, header_fmt)
1101
+
1102
+ # Auto width + col format
1103
+ for i, col in enumerate(self.columns):
1104
+ # Max str len of each column
1105
+ max_len = max(self[col].astype(str).map(len).max(), len(col)) + 2
1106
+ worksheet.set_column(i, i, max_len) # Set width
1107
+
1108
+ # Format style
1109
+ if cols_contain_number is None:
1110
+ continue
1111
+
1112
+ if col in cols_contain_number:
1113
+ worksheet.set_column(i, i, max_len, number_fmt)
1114
+ else:
1115
+ worksheet.set_column(i, i, max_len, text_fmt)
1116
+
1117
+
1021
1118
  # City
1022
1119
  # ---------------------------------------------------------------------------
1023
1120
  class DataAnalystDataFrameCityMixin(DFBase):
@@ -1091,6 +1188,7 @@ class DataAnalystDataFrameCityMixin(DFBase):
1091
1188
  class DADF(
1092
1189
  GetClassMembersMixin,
1093
1190
  DataAnalystDataFrameCityMixin,
1191
+ DataAnalystDataFrameExportMixin,
1094
1192
  DataAnalystDataFrameDateMixin,
1095
1193
  DataAnalystDataFrameOtherMixin,
1096
1194
  DataAnalystDataFrameNAMixin,
@@ -3,7 +3,7 @@ Absfuyu: Data Analysis
3
3
  ----------------------
4
4
  Data Analyst DataFrame - Base/Core
5
5
 
6
- Version: 5.6.1
6
+ Version: 5.7.0
7
7
  Date updated: 12/09/2025 (dd/mm/yyyy)
8
8
  """
9
9
 
@@ -3,7 +3,7 @@ Absfuyu: Data Analysis
3
3
  ----------------------
4
4
  DF Function
5
5
 
6
- Version: 5.6.1
6
+ Version: 5.7.0
7
7
  Date updated: 12/09/2025 (dd/mm/yyyy)
8
8
  """
9
9
 
@@ -3,7 +3,7 @@ Absfuyu: Data Analysis
3
3
  ----------------------
4
4
  Matplotlib Helper
5
5
 
6
- Version: 5.6.1
6
+ Version: 5.7.0
7
7
  Date updated: 12/09/2025 (dd/mm/yyyy)
8
8
  """
9
9
 
@@ -4,7 +4,7 @@ Absfuyu: Data Analysis [W.I.P]
4
4
  Extension for ``pd.DataFrame``
5
5
  (deprecated)
6
6
 
7
- Version: 5.6.1
7
+ Version: 5.7.0
8
8
  Date updated: 12/09/2025 (dd/mm/yyyy)
9
9
  """
10
10
 
@@ -3,8 +3,8 @@ Absfuyu: PDF
3
3
  ------------
4
4
  PDF Tool [W.I.P]
5
5
 
6
- Version: 5.6.1
7
- Date updated: 12/09/2025 (dd/mm/yyyy)
6
+ Version: 5.7.0
7
+ Date updated: 16/09/2025 (dd/mm/yyyy)
8
8
  """
9
9
 
10
10
  # Module level
@@ -41,8 +41,6 @@ else:
41
41
 
42
42
  # Class
43
43
  # ---------------------------------------------------------------------------
44
-
45
-
46
44
  class PDFTool(BaseClass):
47
45
  def __init__(self) -> None:
48
46
  super().__init__()