absfuyu 5.2.0__tar.gz → 5.3.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 (119) hide show
  1. {absfuyu-5.2.0 → absfuyu-5.3.0}/PKG-INFO +1 -1
  2. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/__init__.py +1 -1
  3. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/cli/do_group.py +10 -0
  4. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/core/baseclass.py +30 -0
  5. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/dxt/listext.py +124 -8
  6. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/extra/da/dadf.py +13 -0
  7. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/tools/__init__.py +2 -2
  8. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/tools/inspector.py +17 -3
  9. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/util/path.py +156 -2
  10. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/util/text_table.py +218 -62
  11. {absfuyu-5.2.0 → absfuyu-5.3.0}/tests/test_everything.py +22 -9
  12. {absfuyu-5.2.0 → absfuyu-5.3.0}/tests/test_listext.py +1 -1
  13. {absfuyu-5.2.0 → absfuyu-5.3.0}/tests/test_text_table.py +7 -7
  14. {absfuyu-5.2.0 → absfuyu-5.3.0}/.gitignore +0 -0
  15. {absfuyu-5.2.0 → absfuyu-5.3.0}/LICENSE +0 -0
  16. {absfuyu-5.2.0 → absfuyu-5.3.0}/README.md +0 -0
  17. {absfuyu-5.2.0 → absfuyu-5.3.0}/dev_requirements.txt +0 -0
  18. {absfuyu-5.2.0 → absfuyu-5.3.0}/docs/Makefile +0 -0
  19. {absfuyu-5.2.0 → absfuyu-5.3.0}/docs/_template/versioning.html +0 -0
  20. {absfuyu-5.2.0 → absfuyu-5.3.0}/docs/conf.py +0 -0
  21. {absfuyu-5.2.0 → absfuyu-5.3.0}/docs/index.rst +0 -0
  22. {absfuyu-5.2.0 → absfuyu-5.3.0}/docs/info.md +0 -0
  23. {absfuyu-5.2.0 → absfuyu-5.3.0}/docs/make.bat +0 -0
  24. {absfuyu-5.2.0 → absfuyu-5.3.0}/docs/modules.rst +0 -0
  25. {absfuyu-5.2.0 → absfuyu-5.3.0}/images/Logo Full.png +0 -0
  26. {absfuyu-5.2.0 → absfuyu-5.3.0}/images/Logo Square.png +0 -0
  27. {absfuyu-5.2.0 → absfuyu-5.3.0}/images/Logo White.png +0 -0
  28. {absfuyu-5.2.0 → absfuyu-5.3.0}/images/repository-image-crop.png +0 -0
  29. {absfuyu-5.2.0 → absfuyu-5.3.0}/images/repository-image-white.png +0 -0
  30. {absfuyu-5.2.0 → absfuyu-5.3.0}/images/repository-image.png +0 -0
  31. {absfuyu-5.2.0 → absfuyu-5.3.0}/pyproject.toml +0 -0
  32. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/__main__.py +0 -0
  33. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/cli/__init__.py +0 -0
  34. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/cli/color.py +0 -0
  35. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/cli/config_group.py +0 -0
  36. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/cli/game_group.py +0 -0
  37. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/cli/tool_group.py +0 -0
  38. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/config/__init__.py +0 -0
  39. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/config/config.json +0 -0
  40. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/core/__init__.py +0 -0
  41. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/core/baseclass2.py +0 -0
  42. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/core/decorator.py +0 -0
  43. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/core/docstring.py +0 -0
  44. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/core/dummy_cli.py +0 -0
  45. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/core/dummy_func.py +0 -0
  46. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/dxt/__init__.py +0 -0
  47. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/dxt/dictext.py +0 -0
  48. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/dxt/dxt_support.py +0 -0
  49. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/dxt/intext.py +0 -0
  50. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/dxt/strext.py +0 -0
  51. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/extra/__init__.py +0 -0
  52. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/extra/beautiful.py +0 -0
  53. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/extra/da/__init__.py +0 -0
  54. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/extra/da/dadf_base.py +0 -0
  55. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/extra/da/df_func.py +0 -0
  56. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/extra/da/mplt.py +0 -0
  57. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/extra/data_analysis.py +0 -0
  58. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/fun/__init__.py +0 -0
  59. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/fun/tarot.py +0 -0
  60. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/game/__init__.py +0 -0
  61. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/game/game_stat.py +0 -0
  62. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/game/sudoku.py +0 -0
  63. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/game/tictactoe.py +0 -0
  64. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/game/wordle.py +0 -0
  65. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/general/__init__.py +0 -0
  66. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/general/content.py +0 -0
  67. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/general/human.py +0 -0
  68. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/general/shape.py +0 -0
  69. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/logger.py +0 -0
  70. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/pkg_data/__init__.py +0 -0
  71. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/pkg_data/chemistry.pkl +0 -0
  72. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/pkg_data/deprecated.py +0 -0
  73. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/pkg_data/passwordlib_lzma.pkl +0 -0
  74. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/pkg_data/tarot.pkl +0 -0
  75. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/py.typed +0 -0
  76. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/sort.py +0 -0
  77. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/tools/checksum.py +0 -0
  78. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/tools/converter.py +0 -0
  79. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/tools/generator.py +0 -0
  80. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/tools/keygen.py +0 -0
  81. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/tools/obfuscator.py +0 -0
  82. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/tools/passwordlib.py +0 -0
  83. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/tools/shutdownizer.py +0 -0
  84. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/tools/web.py +0 -0
  85. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/typings.py +0 -0
  86. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/util/__init__.py +0 -0
  87. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/util/api.py +0 -0
  88. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/util/json_method.py +0 -0
  89. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/util/lunar.py +0 -0
  90. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/util/performance.py +0 -0
  91. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/util/shorten_number.py +0 -0
  92. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/util/zipped.py +0 -0
  93. {absfuyu-5.2.0 → absfuyu-5.3.0}/src/absfuyu/version.py +0 -0
  94. {absfuyu-5.2.0 → absfuyu-5.3.0}/tests/__init__.py +0 -0
  95. {absfuyu-5.2.0 → absfuyu-5.3.0}/tests/conftest.py +0 -0
  96. {absfuyu-5.2.0 → absfuyu-5.3.0}/tests/test_api.py +0 -0
  97. {absfuyu-5.2.0 → absfuyu-5.3.0}/tests/test_beautiful.py +0 -0
  98. {absfuyu-5.2.0 → absfuyu-5.3.0}/tests/test_config.py +0 -0
  99. {absfuyu-5.2.0 → absfuyu-5.3.0}/tests/test_converter.py +0 -0
  100. {absfuyu-5.2.0 → absfuyu-5.3.0}/tests/test_core.py +0 -0
  101. {absfuyu-5.2.0 → absfuyu-5.3.0}/tests/test_data_analysis.py +0 -0
  102. {absfuyu-5.2.0 → absfuyu-5.3.0}/tests/test_dictext.py +0 -0
  103. {absfuyu-5.2.0 → absfuyu-5.3.0}/tests/test_extra.py +0 -0
  104. {absfuyu-5.2.0 → absfuyu-5.3.0}/tests/test_fun.py +0 -0
  105. {absfuyu-5.2.0 → absfuyu-5.3.0}/tests/test_game.py +0 -0
  106. {absfuyu-5.2.0 → absfuyu-5.3.0}/tests/test_generator.py +0 -0
  107. {absfuyu-5.2.0 → absfuyu-5.3.0}/tests/test_inspector.py +0 -0
  108. {absfuyu-5.2.0 → absfuyu-5.3.0}/tests/test_intext.py +0 -0
  109. {absfuyu-5.2.0 → absfuyu-5.3.0}/tests/test_logger.py +0 -0
  110. {absfuyu-5.2.0 → absfuyu-5.3.0}/tests/test_obfuscator.py +0 -0
  111. {absfuyu-5.2.0 → absfuyu-5.3.0}/tests/test_passwordlib.py +0 -0
  112. {absfuyu-5.2.0 → absfuyu-5.3.0}/tests/test_performance.py +0 -0
  113. {absfuyu-5.2.0 → absfuyu-5.3.0}/tests/test_pkg_data.py +0 -0
  114. {absfuyu-5.2.0 → absfuyu-5.3.0}/tests/test_shape.py +0 -0
  115. {absfuyu-5.2.0 → absfuyu-5.3.0}/tests/test_shorten_number.py +0 -0
  116. {absfuyu-5.2.0 → absfuyu-5.3.0}/tests/test_strext.py +0 -0
  117. {absfuyu-5.2.0 → absfuyu-5.3.0}/tests/test_tools.py +0 -0
  118. {absfuyu-5.2.0 → absfuyu-5.3.0}/tests/test_util.py +0 -0
  119. {absfuyu-5.2.0 → absfuyu-5.3.0}/tests/test_version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: absfuyu
3
- Version: 5.2.0
3
+ Version: 5.3.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/
@@ -22,7 +22,7 @@ Using in cmd:
22
22
  __title__ = "absfuyu"
23
23
  __author__ = "AbsoluteWinter"
24
24
  __license__ = "MIT License"
25
- __version__ = "5.2.0"
25
+ __version__ = "5.3.0"
26
26
  __all__ = [
27
27
  "core",
28
28
  "config",
@@ -83,6 +83,15 @@ def os_shutdown() -> None:
83
83
  engine.shutdown()
84
84
 
85
85
 
86
+ @click.command(name="organize")
87
+ @click.argument("dir", type=str)
88
+ def organize_directory(dir: str) -> None:
89
+ """Organize a directory"""
90
+ engine = Directory(dir)
91
+ engine.organize()
92
+ click.echo(f"{COLOR['green']}Done!")
93
+
94
+
86
95
  @click.group(name="do")
87
96
  def do_group() -> None:
88
97
  """Perform functionalities"""
@@ -93,3 +102,4 @@ do_group.add_command(update)
93
102
  do_group.add_command(install)
94
103
  do_group.add_command(unzip_files_in_dir)
95
104
  do_group.add_command(os_shutdown)
105
+ do_group.add_command(organize_directory)
@@ -162,6 +162,36 @@ class MethodNPropertyList(NamedTuple):
162
162
 
163
163
  return self.__class__(new_methods_list, [], [], self.properties)
164
164
 
165
+ def sort(self, reverse: bool = False) -> Self:
166
+ """
167
+ Sorts every element in each method list.
168
+
169
+ Parameters
170
+ ----------
171
+ reverse : bool, optional
172
+ Descending order, by default ``False``
173
+
174
+ Returns
175
+ -------
176
+ Self
177
+ Sorted.
178
+
179
+
180
+ Example:
181
+ --------
182
+ >>> test = MethodNPropertyList(["b", "a"], ["d", "c"], ["f", "e"], ["h", "g"])
183
+ >>> test.sort()
184
+ MethodNPropertyList(methods=['a', 'b'], classmethods=['c', 'd'], staticmethods=['e', 'f'], properties=['g', 'h'])
185
+
186
+ >>> test.pack().sort()
187
+ MethodNPropertyList(methods=['a', 'b', 'c <classmethod>', 'd <classmethod>', 'e <staticmethod>', 'f <staticmethod>'], properties=['g', 'h'])
188
+ """
189
+ sorted_vals = [
190
+ sorted(getattr(self, field), reverse=reverse) for field in self._fields
191
+ ]
192
+ # return self._make(sorted_vals)
193
+ return self.__class__(*sorted_vals)
194
+
165
195
 
166
196
  # @versionadded("5.1.0")
167
197
  class MethodNPropertyResult(dict[str, MethodNPropertyList]):
@@ -18,11 +18,12 @@ import operator
18
18
  import random
19
19
  from collections import Counter
20
20
  from collections.abc import Callable, Iterable
21
- from itertools import accumulate, chain, groupby
21
+ from itertools import accumulate, chain, groupby, zip_longest
22
22
  from typing import Any, Literal, Self, cast, overload
23
23
 
24
24
  from absfuyu.core.baseclass import ShowAllMethodsMixin
25
25
  from absfuyu.core.docstring import deprecated, versionadded, versionchanged
26
+ from absfuyu.typings import T as _T
26
27
  from absfuyu.util import set_min_max
27
28
 
28
29
 
@@ -354,6 +355,40 @@ class ListExt(ShowAllMethodsMixin, list):
354
355
  start = max(start, 0)
355
356
  return self.__class__(enumerate(self, start=start))
356
357
 
358
+ @versionadded("5.3.0") # no test case yet
359
+ def transpose(self, fillvalue: _T | None = None, /) -> Self:
360
+ """
361
+ Transpose a list of iterable.
362
+
363
+ Parameters
364
+ ----------
365
+ fillvalue : Any, optional
366
+ A fill value, by default ``None``
367
+
368
+ Returns
369
+ -------
370
+ Self | list[list[T]]
371
+ Transposed list.
372
+
373
+
374
+ Example:
375
+ --------
376
+ >>> ListExt([1, 1, 1, 1]).transpose()
377
+ [(1, 1, 1, 1)]
378
+
379
+ >>> ListExt([[1, 1, 1, 1], [1, 1, 1, 1]]).transpose()
380
+ [(1, 1), (1, 1), (1, 1), (1, 1)]
381
+
382
+ >>> ListExt([[1, 1, 1, 1], [1, 1, 1, 1], [1]]).transpose()
383
+ [(1, 1, 1), (1, 1, None), (1, 1, None), (1, 1, None)]
384
+ """
385
+ try:
386
+ return self.__class__(zip_longest(*self, fillvalue=fillvalue)).apply(list)
387
+ except TypeError: # Dimension of 1
388
+ mod_dat = self.apply(lambda x: [x])
389
+ # return self.__class__(zip_longest(*mod_dat, fillvalue=fillvalue)).apply(list)
390
+ return mod_dat
391
+
357
392
  # Random
358
393
  def pick_one(self) -> Any:
359
394
  """
@@ -620,7 +655,7 @@ class ListExt(ShowAllMethodsMixin, list):
620
655
  return self.__class__(data[i1:i2] for i1, i2 in zip([0] + points[:-1], points))
621
656
 
622
657
  @versionadded("5.1.0")
623
- def split_chunk(self, chunk_size: int) -> Self:
658
+ def split_chunk(self, chunk_size: int, /) -> Self:
624
659
  """
625
660
  Split list into smaller chunks
626
661
 
@@ -643,8 +678,75 @@ class ListExt(ShowAllMethodsMixin, list):
643
678
  slice_points = list(range(0, len(self), max(chunk_size, 1)))[1:]
644
679
  return self.slice_points(slice_points)
645
680
 
681
+ @versionadded("5.3.0") # no test case yet
682
+ def to_column(self, ncols: int, fillvalue: _T | None = None) -> Self:
683
+ """
684
+ Smart convert 1 dimension list to 2 dimension list,
685
+ in which, number of columns = ``ncols``.
686
+
687
+ Parameters
688
+ ----------
689
+ ncols : int
690
+ Number of columns
691
+
692
+ fillvalue : T | None, optional
693
+ Fill value, by default ``None``
694
+
695
+ Returns
696
+ -------
697
+ Self
698
+ Coulumned list.
699
+
700
+
701
+ Example:
702
+ --------
703
+ >>> ins = ListExt(range(1,20))
704
+
705
+ >>> # Normal split chunk
706
+ >>> ins.split_chunk(10)
707
+ [
708
+ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
709
+ [11, 12, 13, 14, 15, 16, 17, 18, 19]
710
+ ]
711
+
712
+ >>> # Column split chunk
713
+ >>> ins.to_column(10)
714
+ [
715
+ [1, 3, 5, 7, 9, 11, 13, 15, 17, 19],
716
+ [2, 4, 6, 8, 10, 12, 14, 16, 18, None]
717
+ ]
718
+ """
719
+ num_of_col = max(ncols, 1)
720
+ len_cols = len(self.split_chunk(num_of_col))
721
+ return self.split_chunk(len_cols).transpose(fillvalue)
722
+
723
+ @overload
724
+ def wrap_to_column(self, width: int, /) -> Self: ...
725
+
726
+ @overload
727
+ def wrap_to_column(
728
+ self,
729
+ width: int,
730
+ /,
731
+ *,
732
+ margin: int = 4,
733
+ sep: str = "",
734
+ fill: str = " ",
735
+ transpose: bool = False,
736
+ ) -> Self: ...
737
+
738
+ @versionchanged("5.3.0", reason="New `sep`, `fill`, `transpose` parameters")
646
739
  @versionadded("5.2.0") # no test case yet
647
- def wrap_to_column(self, width: int, margin: int = 4) -> Self:
740
+ def wrap_to_column(
741
+ self,
742
+ width: int,
743
+ /,
744
+ *,
745
+ margin: int = 4,
746
+ sep: str = "",
747
+ fill: str = " ",
748
+ transpose: bool = False,
749
+ ) -> Self:
648
750
  """
649
751
  Arrange list[str] items into aligned text columns (for printing)
650
752
  with automatic column count calculation.
@@ -655,7 +757,16 @@ class ListExt(ShowAllMethodsMixin, list):
655
757
  Total available display width (must be >= ``margin``)
656
758
 
657
759
  margin : int, optional
658
- Reserved space for borders/padding, by default ``4``
760
+ Reserved space for borders/padding, should be an even number, by default ``4``
761
+
762
+ sep : str, optional
763
+ Separator between each element, by default ``""``
764
+
765
+ fill : str, optional
766
+ Fill character for spacing, must have the length of 1, by default ``" "``
767
+
768
+ transpose : bool, optional
769
+ Smart transpose the columns, by default ``False``
659
770
 
660
771
  Returns
661
772
  -------
@@ -673,8 +784,10 @@ class ListExt(ShowAllMethodsMixin, list):
673
784
  ['apple ', 'banana ', 'cherry ', 'date ']
674
785
  """
675
786
 
676
- max_item_length = self.max_item_len() + 1 # +1 for spacing
677
- available_width = max(width, 4) - max(margin, 2) # Set boundary
787
+ max_item_length = self.max_item_len() + max(len(sep), 1)
788
+ available_width = max(width, 4) - max(margin, 0) # Set boundary
789
+ if len(fill) != 1:
790
+ fill = " "
678
791
 
679
792
  # Calculate how many columns of text
680
793
  column_count = (
@@ -688,8 +801,11 @@ class ListExt(ShowAllMethodsMixin, list):
688
801
 
689
802
  def mod_item(item: list[str]) -> str:
690
803
  # Set width for str item and join them together
691
- return "".join(x.ljust(max_item_length, " ") for x in item)
804
+ return sep.join(x.ljust(max_item_length, fill) for x in item)
692
805
 
693
- mod_chunk = self.split_chunk(column_count).apply(mod_item)
806
+ if transpose:
807
+ mod_chunk = self.to_column(column_count, fillvalue="").apply(mod_item)
808
+ else:
809
+ mod_chunk = self.split_chunk(column_count).apply(mod_item)
694
810
 
695
811
  return mod_chunk
@@ -1136,6 +1136,7 @@ class DADF_WIP(DADF):
1136
1136
  W.I.P - No test cases written
1137
1137
  """
1138
1138
 
1139
+ @versionadded("5.2.0")
1139
1140
  def split_str_column(
1140
1141
  self,
1141
1142
  col: str,
@@ -1165,6 +1166,18 @@ class DADF_WIP(DADF):
1165
1166
  -------
1166
1167
  Self
1167
1168
  DataFrame
1169
+
1170
+
1171
+ Example:
1172
+ --------
1173
+ >>> df = DADF(DADF.sample_df(5)[["text"]])
1174
+ >>> df.split_str_column("text", "s"))
1175
+ text text_0 text_1
1176
+ 0 uwfzbsgj uwfzb gj
1177
+ 1 lxlskayx lxl kayx
1178
+ 2 fzgpzjtp fzgpzjtp None
1179
+ 3 lxnytktz lxnytktz None
1180
+ 4 onryaxtt onryaxtt None
1168
1181
  """
1169
1182
  if n is None:
1170
1183
  pass
@@ -12,7 +12,7 @@ Date updated: 16/03/2025 (dd/mm/yyyy)
12
12
  __all__ = [
13
13
  # # Main
14
14
  "Checksum",
15
- "Base64ED",
15
+ "B64",
16
16
  "T2C",
17
17
  # "Charset",
18
18
  # "Generator",
@@ -26,7 +26,7 @@ __all__ = [
26
26
  # Library
27
27
  # ---------------------------------------------------------------------------
28
28
  from absfuyu.tools.checksum import Checksum
29
- from absfuyu.tools.converter import Base64EncodeDecode as Base64ED
29
+ from absfuyu.tools.converter import Base64EncodeDecode as B64
30
30
  from absfuyu.tools.converter import Text2Chemistry as T2C
31
31
  from absfuyu.tools.inspector import Inspector, inspect_all
32
32
 
@@ -71,6 +71,9 @@ class Inspector(AutoREPRMixin):
71
71
  Maximum lines for the output's header (class, signature, repr).
72
72
  Must be >= 1, by default ``8``
73
73
 
74
+ style : Literal["normal", "bold", "dashed", "double", "rounded"], optional
75
+ Style for the table, by default ``"normal"``
76
+
74
77
 
75
78
  Example:
76
79
  --------
@@ -96,6 +99,7 @@ class Inspector(AutoREPRMixin):
96
99
  include_attribute: bool = True,
97
100
  include_private: bool = False,
98
101
  max_textwrap_lines: int = 8,
102
+ style: Literal["normal", "bold", "dashed", "double", "rounded"] = "normal",
99
103
  ) -> None: ...
100
104
 
101
105
  def __init__(
@@ -114,6 +118,8 @@ class Inspector(AutoREPRMixin):
114
118
  include_attribute: bool = True,
115
119
  include_private: bool = False,
116
120
  include_all: bool = False,
121
+ # Style
122
+ style: Literal["normal", "bold", "dashed", "double", "rounded"] = "normal",
117
123
  ) -> None:
118
124
  """
119
125
  Inspect an object.
@@ -153,6 +159,9 @@ class Inspector(AutoREPRMixin):
153
159
  Maximum lines for the output's header (class, signature, repr).
154
160
  Must be >= 1, by default ``8``
155
161
 
162
+ style : Literal["normal", "bold", "dashed", "double", "rounded"], optional
163
+ Style for the table, by default ``"normal"``
164
+
156
165
 
157
166
  Example:
158
167
  --------
@@ -165,6 +174,7 @@ class Inspector(AutoREPRMixin):
165
174
  self.include_property = include_property
166
175
  self.include_attribute = include_attribute
167
176
  self.include_private = include_private
177
+ self._style = style
168
178
 
169
179
  if include_all:
170
180
  self.include_docs = True
@@ -203,7 +213,9 @@ class Inspector(AutoREPRMixin):
203
213
 
204
214
  # Support
205
215
  def _long_list_terminal_size(self, long_list: list) -> list:
206
- ll = ListExt(long_list).wrap_to_column(self._linelength, margin=4)
216
+ ll = ListExt(long_list).wrap_to_column(
217
+ self._linelength, margin=4, transpose=True
218
+ )
207
219
  return list(ll)
208
220
 
209
221
  # Signature
@@ -392,7 +404,7 @@ class Inspector(AutoREPRMixin):
392
404
 
393
405
  # Output
394
406
  def _make_output(self) -> OneColumnTableMaker:
395
- table = OneColumnTableMaker(self._linelength)
407
+ table = OneColumnTableMaker(self._linelength, style=self._style)
396
408
  body: list[str] = []
397
409
 
398
410
  # Signature
@@ -419,7 +431,9 @@ class Inspector(AutoREPRMixin):
419
431
 
420
432
  # Method & Property
421
433
  try:
422
- method_n_properties = self._get_method_property().flatten_value().pack()
434
+ method_n_properties = (
435
+ self._get_method_property().flatten_value().pack().sort()
436
+ )
423
437
  if self.include_method:
424
438
  ml = [
425
439
  text_shorten(f"- {x}", self._linelength - 4)
@@ -46,6 +46,128 @@ from absfuyu.core.decorator import add_subclass_methods_decorator
46
46
  from absfuyu.core.docstring import deprecated, versionadded, versionchanged
47
47
  from absfuyu.logger import logger
48
48
 
49
+ # Template
50
+ # ---------------------------------------------------------------------------
51
+ ORGANIZE_TEMPLATE: dict[str, list[str]] = {
52
+ "Code": [".ps1", ".py", ".rs", ".js", ".c", ".h", ".cpp", ".r", ".cmd", ".bat"],
53
+ "Comic": [".cbz", ".cbr", ".cb7", ".cbt", ".cba"],
54
+ "Compressed": [
55
+ ".7z",
56
+ ".zip",
57
+ ".rar",
58
+ ".apk",
59
+ ".cab",
60
+ ".tar",
61
+ ".tgz",
62
+ ".txz",
63
+ ".bz2",
64
+ ".gz",
65
+ ".lz",
66
+ ".lz4",
67
+ ".lzma",
68
+ ".xz",
69
+ ".zipx",
70
+ ".zst",
71
+ ],
72
+ "Documents": [".docx", ".doc", ".xls", ".xlsx", ".ppt", ".pptx", ".pdf", ".txt"],
73
+ "Ebook": [
74
+ ".epub",
75
+ ".mobi",
76
+ ".prc",
77
+ ".lrf",
78
+ ".lrx",
79
+ ".pdb",
80
+ ".azw",
81
+ ".azw3",
82
+ ".kf8",
83
+ ".kfx",
84
+ ".opf",
85
+ ],
86
+ "Music": [".mp3", ".flac", ".wav", ".m4a", ".wma", ".aac", ".alac", ".aiff"],
87
+ "OS": [".iso", ".dmg", ".wim"],
88
+ "Pictures": [
89
+ ".jpg",
90
+ ".jpeg",
91
+ ".png",
92
+ ".apng",
93
+ ".avif",
94
+ ".bmp",
95
+ ".gif",
96
+ ".jfif",
97
+ ".pjpeg",
98
+ ".pjp",
99
+ ".svg",
100
+ ".ico",
101
+ ".cur",
102
+ ".tif",
103
+ ".tiff",
104
+ ".webp",
105
+ ],
106
+ "Programs": [".exe", ".msi"],
107
+ "Video": [
108
+ ".3g2",
109
+ ".3gp",
110
+ ".avi",
111
+ ".flv",
112
+ ".m2ts",
113
+ ".m4v",
114
+ ".mkv",
115
+ ".mov",
116
+ ".mp4",
117
+ ".mpeg",
118
+ ".mpv",
119
+ ".mts",
120
+ ".ts",
121
+ ".vob",
122
+ ".webm",
123
+ ],
124
+ "Raw pictures": [
125
+ ".3fr",
126
+ ".ari",
127
+ ".arw",
128
+ ".bay",
129
+ ".braw",
130
+ ".crw",
131
+ ".cr2",
132
+ ".cr3",
133
+ ".cap",
134
+ ".data",
135
+ ".dcs",
136
+ ".dcr",
137
+ ".dng",
138
+ ".drf",
139
+ ".eip",
140
+ ".erf",
141
+ ".fff",
142
+ ".gpr",
143
+ ".iiq",
144
+ ".k25",
145
+ ".kdc",
146
+ ".mdc",
147
+ ".mef",
148
+ ".mos",
149
+ ".mrw",
150
+ ".nef",
151
+ ".nrw",
152
+ ".obm",
153
+ ".orf",
154
+ ".pef",
155
+ ".ptx",
156
+ ".pxn",
157
+ ".r3d",
158
+ ".raf",
159
+ ".raw",
160
+ ".rwl",
161
+ ".rw2",
162
+ ".rwz",
163
+ ".sr2",
164
+ ".srf",
165
+ ".srw",
166
+ ".tif",
167
+ ".x3f",
168
+ ],
169
+ }
170
+
49
171
 
50
172
  # Support Class
51
173
  # ---------------------------------------------------------------------------
@@ -444,10 +566,42 @@ class DirectoryArchiverMixin(DirectoryBase):
444
566
 
445
567
  class DirectoryOrganizerMixin(DirectoryBase):
446
568
  """
447
- Directory - File organizer - SOON
569
+ Directory - File organizer
570
+
571
+ - Organize
448
572
  """
449
573
 
450
- pass
574
+ @versionadded("5.3.0")
575
+ def organize(self, dirtemplate: dict[str, list[str]] | None = None) -> None:
576
+ """
577
+ Organize a directory.
578
+
579
+ Parameters
580
+ ----------
581
+ dirtemplate : dict[str, Collection[str]] | None, optional
582
+ | Template to move file to, by default ``None``.
583
+ | Example: {"Documents": [".txt", ".pdf", ...]}
584
+ """
585
+ if dirtemplate is None:
586
+ template = ORGANIZE_TEMPLATE
587
+ else:
588
+ template = dirtemplate
589
+
590
+ other_dir = self.source_path.joinpath("Others")
591
+ other_dir.mkdir(parents=True, exist_ok=True)
592
+
593
+ for path in self.source_path.iterdir():
594
+ if path.is_dir():
595
+ continue
596
+
597
+ for dir_name, suffixes in template.items():
598
+ if path.suffix.lower() in suffixes:
599
+ move_path = self.source_path.joinpath(dir_name)
600
+ move_path.mkdir(parents=True, exist_ok=True)
601
+ path.rename(move_path.joinpath(path.name))
602
+ break
603
+ else:
604
+ path.rename(other_dir.joinpath(path.name))
451
605
 
452
606
 
453
607
  class DirectoryTreeMixin(DirectoryBase):