absfuyu 5.1.0__py3-none-any.whl → 5.2.0__py3-none-any.whl

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 (73) hide show
  1. absfuyu/__init__.py +1 -1
  2. absfuyu/__main__.py +3 -3
  3. absfuyu/cli/__init__.py +1 -1
  4. absfuyu/cli/color.py +3 -3
  5. absfuyu/cli/config_group.py +2 -2
  6. absfuyu/cli/do_group.py +2 -2
  7. absfuyu/cli/game_group.py +2 -2
  8. absfuyu/cli/tool_group.py +2 -3
  9. absfuyu/config/__init__.py +1 -1
  10. absfuyu/core/__init__.py +1 -1
  11. absfuyu/core/baseclass.py +2 -2
  12. absfuyu/core/baseclass2.py +1 -1
  13. absfuyu/core/decorator.py +4 -4
  14. absfuyu/core/docstring.py +43 -25
  15. absfuyu/core/dummy_cli.py +1 -1
  16. absfuyu/core/dummy_func.py +4 -4
  17. absfuyu/dxt/__init__.py +1 -1
  18. absfuyu/dxt/dictext.py +5 -2
  19. absfuyu/dxt/dxt_support.py +1 -1
  20. absfuyu/dxt/intext.py +5 -2
  21. absfuyu/dxt/listext.py +288 -126
  22. absfuyu/dxt/strext.py +75 -15
  23. absfuyu/extra/__init__.py +1 -1
  24. absfuyu/extra/beautiful.py +1 -1
  25. absfuyu/extra/da/__init__.py +1 -1
  26. absfuyu/extra/da/dadf.py +43 -4
  27. absfuyu/extra/da/dadf_base.py +1 -1
  28. absfuyu/extra/da/df_func.py +1 -1
  29. absfuyu/extra/da/mplt.py +1 -1
  30. absfuyu/extra/data_analysis.py +3 -3
  31. absfuyu/fun/__init__.py +1 -1
  32. absfuyu/fun/tarot.py +1 -1
  33. absfuyu/game/__init__.py +1 -1
  34. absfuyu/game/game_stat.py +1 -1
  35. absfuyu/game/sudoku.py +1 -1
  36. absfuyu/game/tictactoe.py +2 -3
  37. absfuyu/game/wordle.py +1 -1
  38. absfuyu/general/__init__.py +1 -1
  39. absfuyu/general/content.py +2 -2
  40. absfuyu/general/human.py +1 -1
  41. absfuyu/general/shape.py +1 -1
  42. absfuyu/logger.py +1 -1
  43. absfuyu/pkg_data/__init__.py +1 -1
  44. absfuyu/pkg_data/deprecated.py +1 -1
  45. absfuyu/sort.py +1 -1
  46. absfuyu/tools/__init__.py +16 -13
  47. absfuyu/tools/checksum.py +2 -2
  48. absfuyu/tools/converter.py +29 -8
  49. absfuyu/tools/generator.py +251 -110
  50. absfuyu/tools/inspector.py +68 -38
  51. absfuyu/tools/keygen.py +1 -1
  52. absfuyu/tools/obfuscator.py +2 -2
  53. absfuyu/tools/passwordlib.py +3 -4
  54. absfuyu/tools/shutdownizer.py +1 -1
  55. absfuyu/tools/web.py +1 -1
  56. absfuyu/typings.py +136 -0
  57. absfuyu/util/__init__.py +18 -4
  58. absfuyu/util/api.py +36 -16
  59. absfuyu/util/json_method.py +43 -14
  60. absfuyu/util/lunar.py +1 -1
  61. absfuyu/util/path.py +2 -2
  62. absfuyu/util/performance.py +120 -5
  63. absfuyu/util/shorten_number.py +1 -1
  64. absfuyu/util/text_table.py +48 -14
  65. absfuyu/util/zipped.py +4 -3
  66. absfuyu/version.py +2 -2
  67. {absfuyu-5.1.0.dist-info → absfuyu-5.2.0.dist-info}/METADATA +1 -1
  68. absfuyu-5.2.0.dist-info/RECORD +76 -0
  69. absfuyu/core/typings.py +0 -40
  70. absfuyu-5.1.0.dist-info/RECORD +0 -76
  71. {absfuyu-5.1.0.dist-info → absfuyu-5.2.0.dist-info}/WHEEL +0 -0
  72. {absfuyu-5.1.0.dist-info → absfuyu-5.2.0.dist-info}/entry_points.txt +0 -0
  73. {absfuyu-5.1.0.dist-info → absfuyu-5.2.0.dist-info}/licenses/LICENSE +0 -0
@@ -3,21 +3,22 @@ Absfuyu: Inspector
3
3
  ------------------
4
4
  Inspector
5
5
 
6
- Version: 5.1.0
7
- Date updated: 10/03/2025 (dd/mm/yyyy)
6
+ Version: 5.2.0
7
+ Date updated: 16/03/2025 (dd/mm/yyyy)
8
8
  """
9
9
 
10
10
  # Module level
11
11
  # ---------------------------------------------------------------------------
12
- __all__ = ["Inspector"]
12
+ __all__ = ["Inspector", "inspect_all"]
13
13
 
14
14
  # Library
15
15
  # ---------------------------------------------------------------------------
16
- import inspect
16
+ import inspect as _inspect
17
17
  import os
18
+ from functools import partial
18
19
  from textwrap import TextWrapper
19
20
  from textwrap import shorten as text_shorten
20
- from typing import Any
21
+ from typing import Any, Literal, overload
21
22
 
22
23
  from absfuyu.core.baseclass import (
23
24
  AutoREPRMixin,
@@ -33,7 +34,8 @@ from absfuyu.util.text_table import OneColumnTableMaker
33
34
  # TODO: rewrite with each class for docs, method, property, attr, param, title
34
35
  class Inspector(AutoREPRMixin):
35
36
  """
36
- Inspect an object
37
+ Inspect an object.
38
+ By default shows object's docstring and attribute (if any).
37
39
 
38
40
  Parameters
39
41
  ----------
@@ -42,7 +44,7 @@ class Inspector(AutoREPRMixin):
42
44
 
43
45
  line_length: int | None
44
46
  Number of cols in inspect output (Split line every line_length).
45
- Set to ``None`` to use ``os.get_terminal_size()``, by default ``88``
47
+ Set to ``None`` to use ``os.get_terminal_size()``, by default ``None``
46
48
 
47
49
  include_docs : bool, optional
48
50
  Include docstring, by default ``True``
@@ -54,7 +56,7 @@ class Inspector(AutoREPRMixin):
54
56
  Include object's methods (if any), by default ``False``
55
57
 
56
58
  include_property : bool, optional
57
- Include object's properties (if any), by default ``True``
59
+ Include object's properties (if any), by default ``False``
58
60
 
59
61
  include_attribute : bool, optional
60
62
  Include object's attributes (if any), by default ``True``
@@ -65,27 +67,57 @@ class Inspector(AutoREPRMixin):
65
67
  include_all : bool, optional
66
68
  Include all infomation availble, by default ``False``
67
69
 
70
+ max_textwrap_lines : int, optional
71
+ Maximum lines for the output's header (class, signature, repr).
72
+ Must be >= 1, by default ``8``
73
+
68
74
 
69
75
  Example:
70
76
  --------
71
77
  >>> print(Inspector(<object>, **kwargs))
72
78
  """
73
79
 
80
+ @overload
81
+ def __init__(self, obj: Any) -> None: ...
82
+
83
+ @overload
84
+ def __init__(self, obj: Any, *, include_all: Literal[True] = ...) -> None: ...
85
+
86
+ @overload
87
+ def __init__(
88
+ self,
89
+ obj: Any,
90
+ *,
91
+ line_length: int | None = None,
92
+ include_docs: bool = True,
93
+ include_mro: bool = False,
94
+ include_method: bool = False,
95
+ include_property: bool = False,
96
+ include_attribute: bool = True,
97
+ include_private: bool = False,
98
+ max_textwrap_lines: int = 8,
99
+ ) -> None: ...
100
+
74
101
  def __init__(
75
102
  self,
76
103
  obj: Any,
77
104
  *,
78
- line_length: int | None = 88,
105
+ # Line length
106
+ line_length: int | None = None,
107
+ line_length_offset: int = 0, # line_length += line_length_offset (when line_length=None)
108
+ max_textwrap_lines: int = 8,
109
+ # Include
79
110
  include_docs: bool = True,
80
111
  include_mro: bool = False,
81
112
  include_method: bool = False,
82
- include_property: bool = True,
113
+ include_property: bool = False,
83
114
  include_attribute: bool = True,
84
115
  include_private: bool = False,
85
116
  include_all: bool = False,
86
117
  ) -> None:
87
118
  """
88
- Inspect an object
119
+ Inspect an object.
120
+ By default shows object's docstring and attribute (if any).
89
121
 
90
122
  Parameters
91
123
  ----------
@@ -94,7 +126,7 @@ class Inspector(AutoREPRMixin):
94
126
 
95
127
  line_length: int | None
96
128
  Number of cols in inspect output (Split line every line_length).
97
- Set to ``None`` to use ``os.get_terminal_size()``, by default ``88``
129
+ Set to ``None`` to use ``os.get_terminal_size()``, by default ``None``
98
130
 
99
131
  include_docs : bool, optional
100
132
  Include docstring, by default ``True``
@@ -106,7 +138,7 @@ class Inspector(AutoREPRMixin):
106
138
  Include object's methods (if any), by default ``False``
107
139
 
108
140
  include_property : bool, optional
109
- Include object's properties (if any), by default ``True``
141
+ Include object's properties (if any), by default ``False``
110
142
 
111
143
  include_attribute : bool, optional
112
144
  Include object's attributes (if any), by default ``True``
@@ -117,6 +149,10 @@ class Inspector(AutoREPRMixin):
117
149
  include_all : bool, optional
118
150
  Include all infomation availble, by default ``False``
119
151
 
152
+ max_textwrap_lines : int, optional
153
+ Maximum lines for the output's header (class, signature, repr).
154
+ Must be >= 1, by default ``8``
155
+
120
156
 
121
157
  Example:
122
158
  --------
@@ -141,7 +177,7 @@ class Inspector(AutoREPRMixin):
141
177
  # Setup line length
142
178
  if line_length is None:
143
179
  try:
144
- self._linelength = os.get_terminal_size().columns
180
+ self._linelength = os.get_terminal_size().columns + line_length_offset
145
181
  except OSError:
146
182
  self._linelength = 88
147
183
  elif isinstance(line_length, (int, float)):
@@ -156,7 +192,7 @@ class Inspector(AutoREPRMixin):
156
192
  subsequent_indent="",
157
193
  tabsize=4,
158
194
  break_long_words=True,
159
- max_lines=8,
195
+ max_lines=max(max_textwrap_lines, 1),
160
196
  )
161
197
 
162
198
  # Output
@@ -167,18 +203,8 @@ class Inspector(AutoREPRMixin):
167
203
 
168
204
  # Support
169
205
  def _long_list_terminal_size(self, long_list: list) -> list:
170
- max_name_len = max([len(x) for x in long_list]) + 1
171
- cols = 1
172
-
173
- if max_name_len <= self._linelength - 4:
174
- cols = (self._linelength - 4) // max_name_len
175
- splitted_chunk: list[list[str]] = ListExt(long_list).split_chunk(cols)
176
-
177
- mod_chunk = ListExt(
178
- [[x.ljust(max_name_len, " ") for x in chunk] for chunk in splitted_chunk]
179
- ).apply(lambda x: "".join(x))
180
-
181
- return list(mod_chunk)
206
+ ll = ListExt(long_list).wrap_to_column(self._linelength, margin=4)
207
+ return list(ll)
182
208
 
183
209
  # Signature
184
210
  def _make_title(self) -> str:
@@ -189,9 +215,9 @@ class Inspector(AutoREPRMixin):
189
215
  title_str = (
190
216
  str(self.obj)
191
217
  if (
192
- inspect.isclass(self.obj)
218
+ _inspect.isclass(self.obj)
193
219
  or callable(self.obj)
194
- or inspect.ismodule(self.obj)
220
+ or _inspect.ismodule(self.obj)
195
221
  )
196
222
  else str(type(self.obj))
197
223
  )
@@ -199,17 +225,17 @@ class Inspector(AutoREPRMixin):
199
225
 
200
226
  def _get_signature_prefix(self) -> str:
201
227
  # signature prefix
202
- if inspect.isclass(self.obj):
228
+ if _inspect.isclass(self.obj):
203
229
  return "class"
204
- elif inspect.iscoroutinefunction(self.obj):
230
+ elif _inspect.iscoroutinefunction(self.obj):
205
231
  return "async def"
206
- elif inspect.isfunction(self.obj):
232
+ elif _inspect.isfunction(self.obj):
207
233
  return "def"
208
234
  return ""
209
235
 
210
236
  def get_parameters(self) -> list[str] | None:
211
237
  try:
212
- sig = inspect.signature(self.obj)
238
+ sig = _inspect.signature(self.obj)
213
239
  except (ValueError, AttributeError, TypeError):
214
240
  return None
215
241
  return [str(x) for x in sig.parameters.values()]
@@ -221,7 +247,7 @@ class Inspector(AutoREPRMixin):
221
247
  """
222
248
  try:
223
249
  return self._text_wrapper.wrap(
224
- f"{self._get_signature_prefix()} {self.obj.__name__}{inspect.signature(self.obj)}"
250
+ f"{self._get_signature_prefix()} {self.obj.__name__}{_inspect.signature(self.obj)}"
225
251
  )
226
252
  # not class, func | not type | is module
227
253
  except (ValueError, AttributeError, TypeError):
@@ -229,9 +255,8 @@ class Inspector(AutoREPRMixin):
229
255
 
230
256
  # Method and property
231
257
  def _get_method_property(self) -> MethodNPropertyResult:
232
- # if inspect.isclass(self.obj) or inspect.ismodule(self.obj):
233
- if inspect.isclass(self.obj):
234
- # TODO: Support enum type
258
+ # if _inspect.isclass(self.obj) or inspect.ismodule(self.obj):
259
+ if _inspect.isclass(self.obj):
235
260
  tmpcls = type(
236
261
  "tmpcls",
237
262
  (
@@ -271,7 +296,7 @@ class Inspector(AutoREPRMixin):
271
296
  Inspector's workflow:
272
297
  03. Get docstring and strip
273
298
  """
274
- docs: str | None = inspect.getdoc(self.obj)
299
+ docs: str | None = _inspect.getdoc(self.obj)
275
300
 
276
301
  if docs is None:
277
302
  return ""
@@ -431,3 +456,8 @@ class Inspector(AutoREPRMixin):
431
456
 
432
457
  def detail_str(self) -> str:
433
458
  return self._inspect_output.make_table()
459
+
460
+
461
+ # Partial
462
+ # ---------------------------------------------------------------------------
463
+ inspect_all = partial(Inspector, line_length=None, include_all=True)
absfuyu/tools/keygen.py CHANGED
@@ -5,7 +5,7 @@ Mod7 product key generator (90's)
5
5
 
6
6
  This is for educational and informative purposes only.
7
7
 
8
- Version: 5.1.0
8
+ Version: 5.2.0
9
9
  Date updated: 10/03/2025 (dd/mm/yyyy)
10
10
  """
11
11
 
@@ -3,8 +3,8 @@ Absfuyu: Obfuscator
3
3
  -------------------
4
4
  Obfuscate code
5
5
 
6
- Version: 5.1.0
7
- Date updated: 10/03/2025 (dd/mm/yyyy)
6
+ Version: 5.2.0
7
+ Date updated: 11/03/2025 (dd/mm/yyyy)
8
8
  """
9
9
 
10
10
  # Module level
@@ -3,8 +3,8 @@ Absfuyu: Passwordlib
3
3
  --------------------
4
4
  Password library
5
5
 
6
- Version: 5.1.0
7
- Date updated: 10/03/2025 (dd/mm/yyyy)
6
+ Version: 5.2.0
7
+ Date updated: 15/03/2025 (dd/mm/yyyy)
8
8
  """
9
9
 
10
10
  # Module level
@@ -27,7 +27,6 @@ from absfuyu.dxt import DictExt, Text
27
27
  from absfuyu.logger import logger
28
28
  from absfuyu.pkg_data import DataList, DataLoader
29
29
  from absfuyu.tools.generator import Charset, Generator
30
- from absfuyu.util import set_min
31
30
 
32
31
 
33
32
  # Function
@@ -213,7 +212,7 @@ class PasswordGenerator(BaseClass):
213
212
  while True:
214
213
  pwd = Generator.generate_string(
215
214
  charset=charset,
216
- size=set_min(length, min_value=8), # type: ignore
215
+ size=max(length, 8), # type: ignore
217
216
  times=1,
218
217
  string_type_if_1=True,
219
218
  )
@@ -3,7 +3,7 @@ Absfuyu: Shutdownizer
3
3
  ---------------------
4
4
  This shutdowns
5
5
 
6
- Version: 5.1.0
6
+ Version: 5.2.0
7
7
  Date updated: 10/03/2025 (dd/mm/yyyy)
8
8
  """
9
9
 
absfuyu/tools/web.py CHANGED
@@ -3,7 +3,7 @@ Absfuyu: Web
3
3
  ------------
4
4
  Web, ``request``, ``BeautifulSoup`` stuff
5
5
 
6
- Version: 5.1.0
6
+ Version: 5.2.0
7
7
  Date updated: 10/03/2025 (dd/mm/yyyy)
8
8
  """
9
9
 
absfuyu/typings.py ADDED
@@ -0,0 +1,136 @@
1
+ """
2
+ Absfuyu: Core
3
+ -------------
4
+ Pre-defined typing
5
+
6
+ Version: 5.2.0
7
+ Date updated: 14/03/2025 (dd/mm/yyyy)
8
+ """
9
+
10
+ # Module Package
11
+ # ---------------------------------------------------------------------------
12
+ __all__ = [
13
+ # Type
14
+ "T",
15
+ "T_co",
16
+ "T_contra",
17
+ "P",
18
+ "R",
19
+ "_CALLABLE",
20
+ "CT",
21
+ "N",
22
+ "_Number",
23
+ "override",
24
+ # Protocol
25
+ "SupportsShowMethods",
26
+ ]
27
+
28
+
29
+ # Library
30
+ # ---------------------------------------------------------------------------
31
+ from collections.abc import Callable
32
+ from typing import Any, ParamSpec, Protocol, TypeVar, overload
33
+
34
+ try:
35
+ from typing import override # type: ignore
36
+ except ImportError:
37
+ from absfuyu.core.decorator import dummy_decorator as override
38
+
39
+
40
+ # Type
41
+ # ---------------------------------------------------------------------------
42
+ # Types where neither is possible are invariant
43
+ T = TypeVar("T") # Type invariant
44
+ # Type variables that are covariant can be substituted
45
+ # with a more specific type without causing errors
46
+ T_co = TypeVar("T_co", covariant=True) # Type covariant
47
+ # Type variables that are contravariant can be substituted
48
+ # with a more general type without causing errors
49
+ T_contra = TypeVar("T_contra", contravariant=True) # Type contravariant
50
+
51
+ # Callable
52
+ P = ParamSpec("P") # Parameter type
53
+ R = TypeVar("R") # Return type - Can be anything
54
+ _CALLABLE = Callable[P, R]
55
+
56
+ # Class type - Can be any subtype of `type`
57
+ CT = TypeVar("CT", bound=type)
58
+
59
+ # Number type
60
+ N = TypeVar("N", int, float) # Must be int or float
61
+ _Number = int | float
62
+
63
+
64
+ # Protocol
65
+ # ---------------------------------------------------------------------------
66
+ class SupportsShowMethods(Protocol):
67
+ """
68
+ Support class with ``show_all_methods()``
69
+ and ``show_all_properties()`` method
70
+ from ``absfuyu.core.basclass.ShowAllMethodsMixin``
71
+ """
72
+
73
+ @overload
74
+ @classmethod
75
+ def show_all_methods(cls) -> dict[str, list[str]]: ...
76
+
77
+ @overload
78
+ @classmethod
79
+ def show_all_methods(
80
+ cls,
81
+ print_result: bool = False,
82
+ include_classmethod: bool = True,
83
+ classmethod_indicator: str = "<classmethod>",
84
+ include_staticmethod: bool = True,
85
+ staticmethod_indicator: str = "<staticmethod>",
86
+ include_private_method: bool = False,
87
+ ) -> dict[str, list[str]]: ...
88
+
89
+ @classmethod
90
+ def show_all_methods(cls, *args, **kwargs) -> Any: ...
91
+
92
+ @overload
93
+ @classmethod
94
+ def show_all_properties(cls) -> dict[str, list[str]]: ...
95
+
96
+ @overload
97
+ @classmethod
98
+ def show_all_properties(
99
+ cls, print_result: bool = False
100
+ ) -> dict[str, list[str]]: ...
101
+
102
+ @classmethod
103
+ def show_all_properties(cls, *args, **kwargs) -> Any: ...
104
+
105
+
106
+ # Note
107
+ # ---------------------------------------------------------------------------
108
+ # Iterable : __iter__
109
+ # Iterator(Iterable) : __next__, __iter__
110
+ # Reversible(Iterable) : __reversed__, __iter__
111
+ # Sized : __len__
112
+ # Container : __contains__
113
+ # Collection(Sized, Iterable, Container) : __len__, __iter__, __contains__
114
+ # Set(Collection) : __contains__, __iter__, __len__
115
+ # MutableSet(Set) : __contains__, __iter__, __len__
116
+ # Mapping(Collection) : __getitem__, __iter__, and __len__
117
+ # MutableMapping(Mapping) : __getitem__, __setitem__, __delitem__,__iter__, __len__
118
+ # Sequence(Reversible, Collection) : __reversed__, __len__, __iter__, __contains__
119
+ # MutableSequence(Sequence) : __getitem__, __setitem__, __delitem__, __reversed__, __len__, __iter__, __contains__
120
+
121
+ # Iterable : str, dict, list, tuple, set
122
+ # Iterator(Iterable) : Generator
123
+ # Reversible(Iterable) : str, dict, list, tuple
124
+ # Sized : str, dict, list, tuple, set
125
+ # Container : str, dict, list, tuple, set
126
+ # Collection(Sized, Iterable, Container) : str, dict, list, tuple, set
127
+ # Set(Collection) : set
128
+ # MutableSet(Set) : set
129
+ # Mapping(Collection) : dict
130
+ # MutableMapping(Mapping) : dict
131
+ # Sequence(Reversible, Collection) : str, list, tuple
132
+ # MutableSequence(Sequence) : list
133
+
134
+ # __iter__: for <...> in <...>
135
+ # __len__: len(<...>)
136
+ # __contains__: if <...> in <...>
absfuyu/util/__init__.py CHANGED
@@ -3,10 +3,20 @@ Absufyu: Utilities
3
3
  ------------------
4
4
  Some random utilities
5
5
 
6
- Version: 5.1.0
7
- Date updated: 10/03/2025 (dd/mm/yyyy)
6
+ Version: 5.2.0
7
+ Date updated: 12/03/2025 (dd/mm/yyyy)
8
8
  """
9
9
 
10
+ # Module Package
11
+ # ---------------------------------------------------------------------------
12
+ __all__ = [
13
+ "get_installed_package",
14
+ "set_min",
15
+ "set_max",
16
+ "set_min_max",
17
+ "stop_after_day",
18
+ ]
19
+
10
20
  # Library
11
21
  # ---------------------------------------------------------------------------
12
22
  import pkgutil
@@ -137,8 +147,12 @@ def set_min_max(
137
147
  >>> set_min_max(808)
138
148
  100
139
149
  """
140
- current_value = set_min(current_value, min_value=min_value)
141
- current_value = set_max(current_value, max_value=max_value)
150
+ # Set min
151
+ # current_value = set_min(current_value, min_value=min_value)
152
+ current_value = max(current_value, min_value)
153
+ # Set max
154
+ # current_value = set_max(current_value, max_value=max_value)
155
+ current_value = min(current_value, max_value)
142
156
  return current_value
143
157
 
144
158
 
absfuyu/util/api.py CHANGED
@@ -3,8 +3,8 @@ Absufyu: API
3
3
  ------------
4
4
  Fetch data stuff
5
5
 
6
- Version: 5.1.0
7
- Date updated: 10/03/2025 (dd/mm/yyyy)
6
+ Version: 5.2.0
7
+ Date updated: 12/03/2025 (dd/mm/yyyy)
8
8
  """
9
9
 
10
10
  # Module level
@@ -25,7 +25,8 @@ from typing import NamedTuple
25
25
 
26
26
  import requests
27
27
 
28
- from absfuyu.core import versionadded, versionchanged
28
+ from absfuyu.core.baseclass import BaseClass
29
+ from absfuyu.core.docstring import versionadded, versionchanged
29
30
  from absfuyu.logger import logger
30
31
 
31
32
 
@@ -33,8 +34,15 @@ from absfuyu.logger import logger
33
34
  # ---------------------------------------------------------------------------
34
35
  class PingResult(NamedTuple):
35
36
  """
36
- :param host: Host name/IP
37
- :param result: Ping result in ms
37
+ Ping result
38
+
39
+ Parameters
40
+ ----------
41
+ host : str
42
+ Host name/IP
43
+
44
+ result : str
45
+ Ping result in ms
38
46
  """
39
47
 
40
48
  host: str
@@ -90,28 +98,40 @@ def ping_windows(host: list[str], ping_count: int = 3) -> list[PingResult]:
90
98
 
91
99
  # Class
92
100
  # ---------------------------------------------------------------------------
93
- class APIRequest:
94
- """API data with cache feature"""
101
+ class APIRequest(BaseClass):
102
+ """
103
+ API data with cache feature
104
+
105
+ Parameters
106
+ ----------
107
+ api_url : str
108
+ API link
109
+
110
+ encoding : str | None, optional
111
+ Data encoding, by default ``"utf-8"``
112
+ """
95
113
 
96
114
  def __init__(
97
115
  self,
98
116
  api_url: str,
99
- *, # Use "*" to force using keyword in function parameter | Example: APIRequest(url, encoding="utf-8")
117
+ *,
100
118
  encoding: str | None = "utf-8",
101
119
  ) -> None:
102
120
  """
103
- :param api_url: api link
104
- :param encoding: data encoding (Default: utf-8)
121
+ Create APIRequest instance
122
+
123
+ Parameters
124
+ ----------
125
+ api_url : str
126
+ API link
127
+
128
+ encoding : str | None, optional
129
+ Data encoding, by default ``"utf-8"``
105
130
  """
131
+
106
132
  self.url = api_url
107
133
  self.encoding = encoding
108
134
 
109
- def __str__(self) -> str:
110
- return f"{self.__class__.__name__}({self.url})"
111
-
112
- def __repr__(self) -> str:
113
- return self.__str__()
114
-
115
135
  def fetch_data(self, *, update: bool = False, json_cache: str | Path):
116
136
  """
117
137
  Fetch data from an API then cache it for later use
@@ -3,8 +3,8 @@ Absfuyu: Json Method
3
3
  --------------------
4
4
  ``.json`` file handling
5
5
 
6
- Version: 5.1.0
7
- Date updated: 10/03/2025 (dd/mm/yyyy)
6
+ Version: 5.2.0
7
+ Date updated: 12/03/2025 (dd/mm/yyyy)
8
8
  """
9
9
 
10
10
  # Module level
@@ -16,7 +16,6 @@ __all__ = ["JsonFile"]
16
16
  # ---------------------------------------------------------------------------
17
17
  import json
18
18
  from pathlib import Path
19
- from typing import Any
20
19
 
21
20
  from absfuyu.core import BaseClass
22
21
 
@@ -26,6 +25,20 @@ from absfuyu.core import BaseClass
26
25
  class JsonFile(BaseClass):
27
26
  """
28
27
  ``.json`` file handling
28
+
29
+ Parameters
30
+ ----------
31
+ json_file_location : str | Path
32
+ .json file location
33
+
34
+ encoding : str | None, optional
35
+ Data encoding, by default ``"utf-8"``
36
+
37
+ indent : int | str | None, optional
38
+ Indentation when export to json file, by default ``4``
39
+
40
+ sort_keys : bool, optional
41
+ Sort the keys before export to json file, by default ``True``
29
42
  """
30
43
 
31
44
  def __init__(
@@ -37,26 +50,40 @@ class JsonFile(BaseClass):
37
50
  sort_keys: bool = True,
38
51
  ) -> None:
39
52
  """
40
- json_file_location: json file location
41
- encoding: data encoding (Default: utf-8)
42
- indent: indentation when export to json file
43
- sort_keys: sort the keys before export to json file
53
+ ``.json`` file handling
54
+
55
+ Parameters
56
+ ----------
57
+ json_file_location : str | Path
58
+ .json file location
59
+
60
+ encoding : str | None, optional
61
+ Data encoding, by default ``"utf-8"``
62
+
63
+ indent : int | str | None, optional
64
+ Indentation when export to json file, by default ``4``
65
+
66
+ sort_keys : bool, optional
67
+ Sort the keys before export to json file, by default ``True``
44
68
  """
69
+
45
70
  self.json_file_location = Path(json_file_location)
46
71
  self.encoding = encoding
47
72
  self.indent = indent
48
73
  self.sort_keys = sort_keys
49
- self.data: dict[Any, Any] = {}
74
+ self.data: dict = {}
50
75
 
51
76
  def __str__(self) -> str:
52
77
  return f"{self.__class__.__name__}({self.json_file_location.name})"
53
78
 
54
- def load_json(self) -> dict[Any, Any]:
79
+ def load_json(self) -> dict:
55
80
  """
56
81
  Load ``.json`` file
57
82
 
58
- :returns: ``.json`` data
59
- :rtype: dict
83
+ Returns
84
+ -------
85
+ dict
86
+ ``.json`` data
60
87
  """
61
88
  with open(self.json_file_location, "r", encoding=self.encoding) as file:
62
89
  self.data = json.load(file)
@@ -68,11 +95,13 @@ class JsonFile(BaseClass):
68
95
  with open(self.json_file_location, "w", encoding=self.encoding) as file:
69
96
  file.writelines(json_data)
70
97
 
71
- def update_data(self, data: dict[Any, Any]) -> None:
98
+ def update_data(self, data: dict) -> None:
72
99
  """
73
100
  Update ``.json`` data without save
74
101
 
75
- :param data: ``.json`` data
76
- :type data: dict
102
+ Parameters
103
+ ----------
104
+ data : dict
105
+ ``.json`` data
77
106
  """
78
107
  self.data = data