absfuyu 5.6.1__py3-none-any.whl → 5.8.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.
- absfuyu/__init__.py +1 -1
- absfuyu/__main__.py +2 -2
- absfuyu/cli/__init__.py +2 -2
- absfuyu/cli/color.py +2 -2
- absfuyu/cli/config_group.py +2 -2
- absfuyu/cli/do_group.py +2 -2
- absfuyu/cli/game_group.py +2 -2
- absfuyu/cli/tool_group.py +2 -2
- absfuyu/config/__init__.py +2 -2
- absfuyu/core/__init__.py +2 -2
- absfuyu/core/baseclass.py +2 -2
- absfuyu/core/baseclass2.py +2 -2
- absfuyu/core/decorator.py +2 -2
- absfuyu/core/docstring.py +2 -2
- absfuyu/core/dummy_cli.py +2 -2
- absfuyu/core/dummy_func.py +2 -2
- absfuyu/dxt/__init__.py +2 -2
- absfuyu/dxt/dictext.py +2 -2
- absfuyu/dxt/dxt_support.py +2 -2
- absfuyu/dxt/intext.py +2 -2
- absfuyu/dxt/listext.py +2 -2
- absfuyu/dxt/strext.py +2 -2
- absfuyu/extra/__init__.py +2 -2
- absfuyu/extra/beautiful.py +2 -2
- absfuyu/extra/da/__init__.py +4 -2
- absfuyu/extra/da/dadf.py +148 -13
- absfuyu/extra/da/dadf_base.py +2 -2
- absfuyu/extra/da/df_func.py +2 -2
- absfuyu/extra/da/mplt.py +2 -2
- absfuyu/extra/data_analysis.py +2 -2
- absfuyu/extra/pdf.py +2 -4
- absfuyu/extra/xml.py +90 -0
- absfuyu/fun/__init__.py +2 -2
- absfuyu/fun/rubik.py +2 -2
- absfuyu/fun/tarot.py +2 -2
- absfuyu/game/__init__.py +2 -2
- absfuyu/game/game_stat.py +2 -2
- absfuyu/game/sudoku.py +2 -2
- absfuyu/game/tictactoe.py +2 -2
- absfuyu/game/wordle.py +2 -2
- absfuyu/general/__init__.py +2 -2
- absfuyu/general/content.py +2 -2
- absfuyu/general/human.py +2 -2
- absfuyu/general/shape.py +2 -2
- absfuyu/logger.py +2 -2
- absfuyu/pkg_data/__init__.py +2 -2
- absfuyu/pkg_data/deprecated.py +2 -2
- absfuyu/pkg_data/logo.py +1462 -0
- absfuyu/sort.py +2 -2
- absfuyu/tools/__init__.py +2 -2
- absfuyu/tools/checksum.py +2 -2
- absfuyu/tools/converter.py +2 -2
- absfuyu/tools/generator.py +2 -2
- absfuyu/tools/inspector.py +2 -2
- absfuyu/tools/keygen.py +2 -2
- absfuyu/tools/obfuscator.py +2 -2
- absfuyu/tools/passwordlib.py +2 -2
- absfuyu/tools/shutdownizer.py +2 -2
- absfuyu/tools/sw.py +2 -2
- absfuyu/tools/web.py +2 -2
- absfuyu/typings.py +2 -2
- absfuyu/util/__init__.py +2 -2
- absfuyu/util/api.py +2 -2
- absfuyu/util/json_method.py +2 -2
- absfuyu/util/lunar.py +2 -2
- absfuyu/util/path.py +2 -2
- absfuyu/util/performance.py +2 -2
- absfuyu/util/shorten_number.py +2 -2
- absfuyu/util/text_table.py +2 -2
- absfuyu/util/zipped.py +2 -2
- absfuyu/version.py +2 -2
- {absfuyu-5.6.1.dist-info → absfuyu-5.8.0.dist-info}/METADATA +14 -4
- absfuyu-5.8.0.dist-info/RECORD +81 -0
- absfuyu-5.6.1.dist-info/RECORD +0 -79
- {absfuyu-5.6.1.dist-info → absfuyu-5.8.0.dist-info}/WHEEL +0 -0
- {absfuyu-5.6.1.dist-info → absfuyu-5.8.0.dist-info}/entry_points.txt +0 -0
- {absfuyu-5.6.1.dist-info → absfuyu-5.8.0.dist-info}/licenses/LICENSE +0 -0
absfuyu/__init__.py
CHANGED
absfuyu/__main__.py
CHANGED
absfuyu/cli/__init__.py
CHANGED
absfuyu/cli/color.py
CHANGED
absfuyu/cli/config_group.py
CHANGED
absfuyu/cli/do_group.py
CHANGED
absfuyu/cli/game_group.py
CHANGED
absfuyu/cli/tool_group.py
CHANGED
absfuyu/config/__init__.py
CHANGED
absfuyu/core/__init__.py
CHANGED
absfuyu/core/baseclass.py
CHANGED
absfuyu/core/baseclass2.py
CHANGED
absfuyu/core/decorator.py
CHANGED
absfuyu/core/docstring.py
CHANGED
absfuyu/core/dummy_cli.py
CHANGED
absfuyu/core/dummy_func.py
CHANGED
absfuyu/dxt/__init__.py
CHANGED
absfuyu/dxt/dictext.py
CHANGED
absfuyu/dxt/dxt_support.py
CHANGED
absfuyu/dxt/intext.py
CHANGED
absfuyu/dxt/listext.py
CHANGED
absfuyu/dxt/strext.py
CHANGED
absfuyu/extra/__init__.py
CHANGED
absfuyu/extra/beautiful.py
CHANGED
absfuyu/extra/da/__init__.py
CHANGED
|
@@ -3,8 +3,8 @@ Absfuyu: Data Analysis
|
|
|
3
3
|
----------------------
|
|
4
4
|
Data Analyst
|
|
5
5
|
|
|
6
|
-
Version: 5.
|
|
7
|
-
Date updated:
|
|
6
|
+
Version: 5.8.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
|
|
absfuyu/extra/da/dadf.py
CHANGED
|
@@ -3,8 +3,8 @@ Absfuyu: Data Analysis
|
|
|
3
3
|
----------------------
|
|
4
4
|
Data Analyst DataFrame
|
|
5
5
|
|
|
6
|
-
Version: 5.
|
|
7
|
-
Date updated:
|
|
6
|
+
Version: 5.8.0
|
|
7
|
+
Date updated: 17/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
|
|
@@ -38,7 +41,7 @@ except ImportError:
|
|
|
38
41
|
from absfuyu.core.decorator import dummy_decorator as override
|
|
39
42
|
|
|
40
43
|
from absfuyu.core.baseclass import GetClassMembersMixin
|
|
41
|
-
from absfuyu.core.docstring import deprecated, versionadded
|
|
44
|
+
from absfuyu.core.docstring import deprecated, versionadded, versionchanged
|
|
42
45
|
from absfuyu.extra.da.dadf_base import CityData
|
|
43
46
|
from absfuyu.extra.da.dadf_base import DataAnalystDataFrameBase as DFBase
|
|
44
47
|
from absfuyu.extra.da.dadf_base import SplittedDF
|
|
@@ -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
|
# ---------------------------------------------------------------------------
|
|
@@ -342,7 +366,7 @@ class DataAnalystDataFrameInfoMixin(DFBase):
|
|
|
342
366
|
return info
|
|
343
367
|
|
|
344
368
|
@override
|
|
345
|
-
def describe(self, percentiles=None, include=None, exclude=None) -> Self:
|
|
369
|
+
def describe(self, percentiles=None, include=None, exclude=None) -> Self: # type: ignore
|
|
346
370
|
"""pd.DataFrame.describe() override"""
|
|
347
371
|
return self.__class__(super().describe(percentiles, include, exclude)) # type: ignore [no-any-return]
|
|
348
372
|
|
|
@@ -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,105 @@ 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
|
+
@versionchanged("5.8.0", "New parameter")
|
|
1055
|
+
def da_export(
|
|
1056
|
+
self,
|
|
1057
|
+
path: str,
|
|
1058
|
+
sheet_name: str = "Sheet1",
|
|
1059
|
+
*,
|
|
1060
|
+
auto_width: bool = True,
|
|
1061
|
+
cols_contain_centered_text: list[str] | None = None,
|
|
1062
|
+
cols_contain_number: list[str] | None = None,
|
|
1063
|
+
cols_contain_percentage: list[str] | None = None,
|
|
1064
|
+
) -> None:
|
|
1065
|
+
"""
|
|
1066
|
+
Export DataFrame with `xlsxwriter` engine
|
|
1067
|
+
|
|
1068
|
+
Parameters
|
|
1069
|
+
----------
|
|
1070
|
+
path : Path | str
|
|
1071
|
+
Path to export
|
|
1072
|
+
|
|
1073
|
+
sheet_name : str, optional
|
|
1074
|
+
Sheet name, by default "Sheet1"
|
|
1075
|
+
|
|
1076
|
+
auto_width : bool, optional
|
|
1077
|
+
Auto resize column width, by default ``True``
|
|
1078
|
+
|
|
1079
|
+
cols_contain_centered_text : list[str] | None, optional
|
|
1080
|
+
Columns that contain centered text (Align center), by default None
|
|
1081
|
+
|
|
1082
|
+
cols_contain_number : list[str] | None, optional
|
|
1083
|
+
Columns that contain number value (to format as number - int), by default None
|
|
1084
|
+
|
|
1085
|
+
cols_contain_percentage : list[str] | None, optional
|
|
1086
|
+
Columns that contain percentage value (to format as percentage), by default None
|
|
1087
|
+
"""
|
|
1088
|
+
|
|
1089
|
+
# Using xlsxwriter engine
|
|
1090
|
+
with pd.ExcelWriter(path, engine="xlsxwriter") as writer:
|
|
1091
|
+
self.to_excel(writer, sheet_name=sheet_name, index=False, float_format="%.2f", na_rep="")
|
|
1092
|
+
|
|
1093
|
+
# Format style
|
|
1094
|
+
workbook: Workbook = writer.book # type: ignore
|
|
1095
|
+
header_fmt = workbook.add_format(
|
|
1096
|
+
{
|
|
1097
|
+
"bold": True,
|
|
1098
|
+
"text_wrap": True,
|
|
1099
|
+
"border": 1,
|
|
1100
|
+
"align": "center",
|
|
1101
|
+
"valign": "vcenter",
|
|
1102
|
+
# "bg_color": "#A0BEFD",
|
|
1103
|
+
}
|
|
1104
|
+
)
|
|
1105
|
+
number_fmt = workbook.add_format(
|
|
1106
|
+
{"num_format": "#,##0", "align": "center", "valign": "vcenter"}
|
|
1107
|
+
) # 1,000,000
|
|
1108
|
+
percent_fmt = workbook.add_format({"num_format": "0.00%", "align": "center", "valign": "vcenter"}) # 1.00%
|
|
1109
|
+
text_fmt = workbook.add_format({"valign": "vcenter"})
|
|
1110
|
+
text_center_fmt = workbook.add_format({"align": "center", "valign": "vcenter"})
|
|
1111
|
+
|
|
1112
|
+
# Format sheet
|
|
1113
|
+
worksheet: Worksheet = writer.sheets[sheet_name]
|
|
1114
|
+
|
|
1115
|
+
# Format header - First row
|
|
1116
|
+
for col_num, value in enumerate(self.columns.values):
|
|
1117
|
+
worksheet.write(0, col_num, value, header_fmt)
|
|
1118
|
+
|
|
1119
|
+
rules = [
|
|
1120
|
+
(cols_contain_number, number_fmt),
|
|
1121
|
+
(cols_contain_percentage, percent_fmt),
|
|
1122
|
+
(cols_contain_centered_text, text_center_fmt),
|
|
1123
|
+
]
|
|
1124
|
+
|
|
1125
|
+
# Auto width + col format
|
|
1126
|
+
for i, col in enumerate(self.columns):
|
|
1127
|
+
# Max str len of each column
|
|
1128
|
+
max_len = None if auto_width is None else max(self[col].astype(str).map(len).max(), len(col)) + 2
|
|
1129
|
+
worksheet.set_column(i, i, max_len) # Set width
|
|
1130
|
+
|
|
1131
|
+
# Format style
|
|
1132
|
+
fmt = text_fmt # default
|
|
1133
|
+
for cols, f in rules:
|
|
1134
|
+
if cols is not None and col in cols:
|
|
1135
|
+
fmt = f
|
|
1136
|
+
break
|
|
1137
|
+
worksheet.set_column(i, i, max_len, fmt)
|
|
1138
|
+
|
|
1139
|
+
# if cols_contain_number is not None:
|
|
1140
|
+
# for x in cols_contain_number:
|
|
1141
|
+
# self[x] = pd.to_numeric(self[x], errors="coerce")
|
|
1142
|
+
|
|
1143
|
+
|
|
1021
1144
|
# City
|
|
1022
1145
|
# ---------------------------------------------------------------------------
|
|
1023
1146
|
class DataAnalystDataFrameCityMixin(DFBase):
|
|
@@ -1091,6 +1214,7 @@ class DataAnalystDataFrameCityMixin(DFBase):
|
|
|
1091
1214
|
class DADF(
|
|
1092
1215
|
GetClassMembersMixin,
|
|
1093
1216
|
DataAnalystDataFrameCityMixin,
|
|
1217
|
+
DataAnalystDataFrameExportMixin,
|
|
1094
1218
|
DataAnalystDataFrameDateMixin,
|
|
1095
1219
|
DataAnalystDataFrameOtherMixin,
|
|
1096
1220
|
DataAnalystDataFrameNAMixin,
|
|
@@ -1191,3 +1315,14 @@ class DADF_WIP(DADF):
|
|
|
1191
1315
|
"""
|
|
1192
1316
|
|
|
1193
1317
|
pass
|
|
1318
|
+
|
|
1319
|
+
if __name__ == "__main__":
|
|
1320
|
+
from pathlib import Path
|
|
1321
|
+
|
|
1322
|
+
t = DADF.sample_df().show_distribution("number_range", show_percentage=False)
|
|
1323
|
+
t.da_export(
|
|
1324
|
+
Path(__file__).parent.joinpath("a.xlsx").resolve().__str__(),
|
|
1325
|
+
cols_contain_number=["number_range"],
|
|
1326
|
+
cols_contain_percentage=["percentage"],
|
|
1327
|
+
)
|
|
1328
|
+
print(t)
|
absfuyu/extra/da/dadf_base.py
CHANGED
absfuyu/extra/da/df_func.py
CHANGED
absfuyu/extra/da/mplt.py
CHANGED
absfuyu/extra/data_analysis.py
CHANGED
absfuyu/extra/pdf.py
CHANGED
|
@@ -3,8 +3,8 @@ Absfuyu: PDF
|
|
|
3
3
|
------------
|
|
4
4
|
PDF Tool [W.I.P]
|
|
5
5
|
|
|
6
|
-
Version: 5.
|
|
7
|
-
Date updated:
|
|
6
|
+
Version: 5.8.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__()
|