absfuyu 5.6.1__py3-none-any.whl → 6.1.3__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 (102) hide show
  1. absfuyu/__init__.py +5 -3
  2. absfuyu/__main__.py +2 -2
  3. absfuyu/cli/__init__.py +13 -2
  4. absfuyu/cli/audio_group.py +98 -0
  5. absfuyu/cli/color.py +2 -2
  6. absfuyu/cli/config_group.py +2 -2
  7. absfuyu/cli/do_group.py +2 -2
  8. absfuyu/cli/game_group.py +20 -2
  9. absfuyu/cli/tool_group.py +68 -4
  10. absfuyu/config/__init__.py +3 -3
  11. absfuyu/core/__init__.py +10 -6
  12. absfuyu/core/baseclass.py +104 -34
  13. absfuyu/core/baseclass2.py +43 -2
  14. absfuyu/core/decorator.py +2 -2
  15. absfuyu/core/docstring.py +4 -2
  16. absfuyu/core/dummy_cli.py +3 -3
  17. absfuyu/core/dummy_func.py +2 -2
  18. absfuyu/dxt/__init__.py +2 -2
  19. absfuyu/dxt/base_type.py +93 -0
  20. absfuyu/dxt/dictext.py +188 -6
  21. absfuyu/dxt/dxt_support.py +2 -2
  22. absfuyu/dxt/intext.py +72 -4
  23. absfuyu/dxt/listext.py +495 -23
  24. absfuyu/dxt/strext.py +2 -2
  25. absfuyu/extra/__init__.py +2 -2
  26. absfuyu/extra/audio/__init__.py +8 -0
  27. absfuyu/extra/audio/_util.py +57 -0
  28. absfuyu/extra/audio/convert.py +192 -0
  29. absfuyu/extra/audio/lossless.py +281 -0
  30. absfuyu/extra/beautiful.py +2 -2
  31. absfuyu/extra/da/__init__.py +39 -3
  32. absfuyu/extra/da/dadf.py +458 -29
  33. absfuyu/extra/da/dadf_base.py +2 -2
  34. absfuyu/extra/da/df_func.py +89 -5
  35. absfuyu/extra/da/mplt.py +2 -2
  36. absfuyu/extra/ggapi/__init__.py +8 -0
  37. absfuyu/extra/ggapi/gdrive.py +223 -0
  38. absfuyu/extra/ggapi/glicense.py +148 -0
  39. absfuyu/extra/ggapi/glicense_df.py +186 -0
  40. absfuyu/extra/ggapi/gsheet.py +88 -0
  41. absfuyu/extra/img/__init__.py +30 -0
  42. absfuyu/extra/img/converter.py +402 -0
  43. absfuyu/extra/img/dup_check.py +291 -0
  44. absfuyu/extra/pdf.py +4 -6
  45. absfuyu/extra/rclone.py +253 -0
  46. absfuyu/extra/xml.py +90 -0
  47. absfuyu/fun/__init__.py +2 -20
  48. absfuyu/fun/rubik.py +2 -2
  49. absfuyu/fun/tarot.py +2 -2
  50. absfuyu/game/__init__.py +2 -2
  51. absfuyu/game/game_stat.py +2 -2
  52. absfuyu/game/schulte.py +78 -0
  53. absfuyu/game/sudoku.py +2 -2
  54. absfuyu/game/tictactoe.py +2 -2
  55. absfuyu/game/wordle.py +6 -4
  56. absfuyu/general/__init__.py +2 -2
  57. absfuyu/general/content.py +2 -2
  58. absfuyu/general/human.py +2 -2
  59. absfuyu/general/resrel.py +213 -0
  60. absfuyu/general/shape.py +3 -8
  61. absfuyu/general/tax.py +344 -0
  62. absfuyu/logger.py +806 -59
  63. absfuyu/numbers/__init__.py +13 -0
  64. absfuyu/numbers/number_to_word.py +321 -0
  65. absfuyu/numbers/shorten_number.py +303 -0
  66. absfuyu/numbers/time_duration.py +217 -0
  67. absfuyu/pkg_data/__init__.py +2 -2
  68. absfuyu/pkg_data/deprecated.py +2 -2
  69. absfuyu/pkg_data/logo.py +1462 -0
  70. absfuyu/sort.py +4 -4
  71. absfuyu/tools/__init__.py +2 -2
  72. absfuyu/tools/checksum.py +119 -4
  73. absfuyu/tools/converter.py +2 -2
  74. absfuyu/tools/generator.py +24 -7
  75. absfuyu/tools/inspector.py +2 -2
  76. absfuyu/tools/keygen.py +2 -2
  77. absfuyu/tools/obfuscator.py +2 -2
  78. absfuyu/tools/passwordlib.py +2 -2
  79. absfuyu/tools/shutdownizer.py +3 -8
  80. absfuyu/tools/sw.py +213 -10
  81. absfuyu/tools/web.py +10 -13
  82. absfuyu/typings.py +5 -8
  83. absfuyu/util/__init__.py +31 -2
  84. absfuyu/util/api.py +7 -4
  85. absfuyu/util/cli.py +119 -0
  86. absfuyu/util/gui.py +91 -0
  87. absfuyu/util/json_method.py +2 -2
  88. absfuyu/util/lunar.py +2 -2
  89. absfuyu/util/package.py +124 -0
  90. absfuyu/util/path.py +313 -4
  91. absfuyu/util/performance.py +2 -2
  92. absfuyu/util/shorten_number.py +206 -13
  93. absfuyu/util/text_table.py +2 -2
  94. absfuyu/util/zipped.py +2 -2
  95. absfuyu/version.py +22 -19
  96. {absfuyu-5.6.1.dist-info → absfuyu-6.1.3.dist-info}/METADATA +37 -8
  97. absfuyu-6.1.3.dist-info/RECORD +105 -0
  98. {absfuyu-5.6.1.dist-info → absfuyu-6.1.3.dist-info}/WHEEL +1 -1
  99. absfuyu/extra/data_analysis.py +0 -21
  100. absfuyu-5.6.1.dist-info/RECORD +0 -79
  101. {absfuyu-5.6.1.dist-info → absfuyu-6.1.3.dist-info}/entry_points.txt +0 -0
  102. {absfuyu-5.6.1.dist-info → absfuyu-6.1.3.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,217 @@
1
+ """
2
+ Absfuyu: Time duration
3
+ ----------------------
4
+ Short time
5
+
6
+ Version: 6.1.2
7
+ Date updated: 30/12/2025 (dd/mm/yyyy)
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ # Module level
13
+ # ---------------------------------------------------------------------------
14
+ __all__ = [
15
+ "Duration",
16
+ ]
17
+
18
+
19
+ # Library
20
+ # ---------------------------------------------------------------------------
21
+ from dataclasses import dataclass, field
22
+ from typing import Protocol, Self
23
+
24
+ from absfuyu.core import versionadded
25
+
26
+
27
+ # Class - Duration
28
+ # ---------------------------------------------------------------------------
29
+ # Format preset
30
+ class SupportDurationFormatPreset(Protocol):
31
+ def __call__(self, duration: Duration, /) -> str: ...
32
+
33
+
34
+ @dataclass
35
+ @versionadded("5.16.0")
36
+ class Duration:
37
+ """
38
+ Convert duration in seconds to a more readable form. Eg: 3 mins 2 secs
39
+
40
+ Parameters
41
+ ----------
42
+ total_seconds : int | float
43
+ Seconds to convert to
44
+ """
45
+
46
+ total_seconds: int | float
47
+
48
+ years: int = field(init=False)
49
+ months: int = field(init=False)
50
+ days: int = field(init=False)
51
+ hours: int = field(init=False)
52
+ minutes: int = field(init=False)
53
+ seconds: int = field(init=False)
54
+
55
+ _formats: dict[str, SupportDurationFormatPreset] = field(init=False)
56
+
57
+ # Calculate duration
58
+ def _calculate_duration(self) -> None:
59
+ SEC_PER_MIN = 60
60
+ SEC_PER_HOUR = 3600
61
+ SEC_PER_DAY = 86400
62
+ SEC_PER_MONTH = 30 * SEC_PER_DAY
63
+ SEC_PER_YEAR = 365 * SEC_PER_DAY
64
+
65
+ secs = self.total_seconds
66
+
67
+ self.years, secs = divmod(secs, SEC_PER_YEAR)
68
+ self.months, secs = divmod(secs, SEC_PER_MONTH)
69
+ self.days, secs = divmod(secs, SEC_PER_DAY)
70
+ self.hours, secs = divmod(secs, SEC_PER_HOUR)
71
+ self.minutes, self.seconds = divmod(secs, SEC_PER_MIN)
72
+
73
+ # Format handling
74
+ def _init_format(self) -> None:
75
+
76
+ def duration_compact_preset(duration: Self, /) -> str:
77
+ """
78
+ Example: "1y 2m 3d 4h 5m 6s"
79
+ (fields = hidden when = 0).
80
+ """
81
+ parts = []
82
+ if duration.years:
83
+ parts.append(f"{duration.years}y")
84
+ if duration.months:
85
+ parts.append(f"{duration.months}m")
86
+ if duration.days:
87
+ parts.append(f"{duration.days}d")
88
+ if duration.hours:
89
+ parts.append(f"{duration.hours}h")
90
+ if duration.minutes:
91
+ parts.append(f"{duration.minutes}m")
92
+ if duration.seconds:
93
+ parts.append(f"{duration.seconds}s")
94
+ return " ".join(parts) if parts else "0s"
95
+
96
+ def duration_HMS_only_preset(duration: Self, /) -> str:
97
+ """
98
+ Example: "02:15:09" (HH:MM:SS only).
99
+ """
100
+ total = duration.total_seconds
101
+ h, m = divmod(total, 3600)
102
+ m, s = divmod(m, 60)
103
+ return f"{h:02d}:{m:02d}:{s:02d}"
104
+
105
+ def duration_digital_preset(duration: Self, /) -> str:
106
+ """
107
+ Examples:
108
+ - If >= 1 day: "1d 02:03:04"
109
+ - else: "02:03:04"
110
+ """
111
+ total = duration.total_seconds
112
+ days, sec = divmod(total, 86400)
113
+ h, sec = divmod(sec, 3600)
114
+ m, s = divmod(sec, 60)
115
+
116
+ if days:
117
+ return f"{days}d {h:02d}:{m:02d}:{s:02d}"
118
+ return f"{h:02d}:{m:02d}:{s:02d}"
119
+
120
+ self._formats = {
121
+ "compact": duration_compact_preset,
122
+ "hms": duration_HMS_only_preset,
123
+ "digital": duration_digital_preset,
124
+ }
125
+
126
+ @versionadded("5.17.0")
127
+ def add_format(self, name: str, format_func: SupportDurationFormatPreset) -> None:
128
+ """
129
+ Add format style to Duration
130
+
131
+ Parameters
132
+ ----------
133
+ name : str
134
+ Name of the style (name will be lowercased)
135
+
136
+ format_func : SupportDurationFormatPreset
137
+ Format function
138
+ """
139
+ self._formats[name.lower().strip()] = format_func
140
+
141
+ @property
142
+ def available_formats(self) -> list[str]:
143
+ """
144
+ Available style format
145
+
146
+ Returns
147
+ -------
148
+ list[str]
149
+ All available style formats
150
+ """
151
+ return list(self._formats)
152
+
153
+ def __format__(self, format_spec: str) -> str:
154
+ """
155
+ Change format of an object.
156
+
157
+ Usage
158
+ -----
159
+ >>> print(f"{<object>:<format_spec>}")
160
+ >>> print(<object>.__format__(<format_spec>))
161
+ >>> print(format(<object>, <format_spec>))
162
+ """
163
+
164
+ func = self._formats.get(format_spec.lower().strip(), None)
165
+
166
+ if func is None:
167
+ return self.__str__()
168
+ else:
169
+ return func(self)
170
+
171
+ # POST INIT
172
+ def __post_init__(self) -> None:
173
+ if not isinstance(self.total_seconds, (int, float)) or self.total_seconds < 0:
174
+ raise ValueError("seconds must be a non-negative number")
175
+ self._calculate_duration()
176
+ self._init_format()
177
+
178
+ def __str__(self) -> str:
179
+
180
+ def _plural(n: int | float, word: str):
181
+ return f"{n} {word}{'s' if n != 1 else ''}"
182
+
183
+ parts = []
184
+ if self.years:
185
+ parts.append(_plural(self.years, "year"))
186
+ if self.months:
187
+ parts.append(_plural(self.months, "month"))
188
+ if self.days:
189
+ parts.append(_plural(self.days, "day"))
190
+ if self.hours:
191
+ parts.append(_plural(self.hours, "hour"))
192
+ if self.minutes:
193
+ parts.append(_plural(self.minutes, "minute"))
194
+ if self.seconds:
195
+ parts.append(_plural(self.seconds, "second"))
196
+ return " ".join(parts) if parts else "0 second"
197
+
198
+ # From other type of duration
199
+ @classmethod
200
+ def from_minute(cls, minutes: int | float) -> Self:
201
+ return cls(minutes * 60)
202
+
203
+ @classmethod
204
+ def from_hour(cls, hours: int | float) -> Self:
205
+ return cls(hours * 3600)
206
+
207
+ @classmethod
208
+ def from_day(cls, days: int | float) -> Self:
209
+ return cls(days * 86400)
210
+
211
+ @classmethod
212
+ def from_month(cls, months: int | float) -> Self:
213
+ return cls(months * 86400 * 30)
214
+
215
+ @classmethod
216
+ def from_year(cls, years: int | float) -> Self:
217
+ return cls(years * 86400 * 365)
@@ -3,8 +3,8 @@ Absfuyu: Package data
3
3
  ---------------------
4
4
  Load package data
5
5
 
6
- Version: 5.6.1
7
- Date updated: 12/09/2025 (dd/mm/yyyy)
6
+ Version: 6.1.2
7
+ Date updated: 30/12/2025 (dd/mm/yyyy)
8
8
  """
9
9
 
10
10
  # Module level
@@ -3,8 +3,8 @@ Absfuyu: Package data
3
3
  ---------------------
4
4
  Deprecated (but might have some use)
5
5
 
6
- Version: 5.6.1
7
- Date updated: 12/09/2025 (dd/mm/yyyy)
6
+ Version: 6.1.2
7
+ Date updated: 30/12/2025 (dd/mm/yyyy)
8
8
  """
9
9
 
10
10
  # Library