absfuyu 5.8.0__py3-none-any.whl → 5.9.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 +37 -3
- absfuyu/extra/da/dadf.py +2 -2
- 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 -2
- absfuyu/extra/rclone.py +253 -0
- absfuyu/extra/xml.py +2 -2
- 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 +2 -2
- 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 +76 -5
- absfuyu/tools/web.py +2 -2
- absfuyu/typings.py +2 -2
- absfuyu/util/__init__.py +31 -2
- absfuyu/util/api.py +2 -2
- absfuyu/util/gui.py +32 -0
- 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.8.0.dist-info → absfuyu-5.9.0.dist-info}/METADATA +4 -1
- absfuyu-5.9.0.dist-info/RECORD +83 -0
- absfuyu-5.8.0.dist-info/RECORD +0 -81
- {absfuyu-5.8.0.dist-info → absfuyu-5.9.0.dist-info}/WHEEL +0 -0
- {absfuyu-5.8.0.dist-info → absfuyu-5.9.0.dist-info}/entry_points.txt +0 -0
- {absfuyu-5.8.0.dist-info → absfuyu-5.9.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,13 +3,19 @@ Absfuyu: Data Analysis
|
|
|
3
3
|
----------------------
|
|
4
4
|
Data Analyst
|
|
5
5
|
|
|
6
|
-
Version: 5.
|
|
7
|
-
Date updated:
|
|
6
|
+
Version: 5.9.0
|
|
7
|
+
Date updated: 23/09/2025 (dd/mm/yyyy)
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
# Module level
|
|
11
11
|
# ---------------------------------------------------------------------------
|
|
12
|
-
__all__ = [
|
|
12
|
+
__all__ = [
|
|
13
|
+
"MatplotlibFormatString",
|
|
14
|
+
"DADF",
|
|
15
|
+
# Function
|
|
16
|
+
"custom_pandas_settings",
|
|
17
|
+
"reset_custom_pandas_settings",
|
|
18
|
+
]
|
|
13
19
|
|
|
14
20
|
|
|
15
21
|
# Library
|
|
@@ -36,3 +42,31 @@ else:
|
|
|
36
42
|
|
|
37
43
|
from absfuyu.extra.da.dadf import DADF
|
|
38
44
|
from absfuyu.extra.da.mplt import MatplotlibFormatString
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
# Function
|
|
48
|
+
# ---------------------------------------------------------------------------
|
|
49
|
+
def custom_pandas_settings(*, show_all_rows: bool = False) -> None:
|
|
50
|
+
"""
|
|
51
|
+
Custom pandas settings. Currently only show all cols/rows
|
|
52
|
+
|
|
53
|
+
Parameters
|
|
54
|
+
----------
|
|
55
|
+
show_all_rows : bool, optional
|
|
56
|
+
Show all rows, by default False
|
|
57
|
+
"""
|
|
58
|
+
# Shows all columns
|
|
59
|
+
pd.set_option("display.max_columns", None) # type: ignore
|
|
60
|
+
|
|
61
|
+
if show_all_rows:
|
|
62
|
+
# (optional) also show all rows if needed
|
|
63
|
+
pd.set_option("display.max_rows", None) # type: ignore
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def reset_custom_pandas_settings() -> None:
|
|
67
|
+
"""
|
|
68
|
+
Reset custom pandas settings
|
|
69
|
+
"""
|
|
70
|
+
settings = ["display.max_columns", "display.max_rows"]
|
|
71
|
+
for x in settings:
|
|
72
|
+
pd.reset_option(x) # type: ignore
|
absfuyu/extra/da/dadf.py
CHANGED
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
absfuyu/extra/rclone.py
ADDED
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Absfuyu: Rclone decrypt
|
|
3
|
+
-----------------------
|
|
4
|
+
Rclone decryptor
|
|
5
|
+
|
|
6
|
+
Version: 5.9.0
|
|
7
|
+
Date updated: 23/09/2025 (dd/mm/yyyy)
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
# Module level
|
|
11
|
+
# ---------------------------------------------------------------------------
|
|
12
|
+
__all__ = ["RcloneEncryptDecrypt", "DirectoryRcloneDEMixin"]
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# Library
|
|
16
|
+
# ---------------------------------------------------------------------------
|
|
17
|
+
import os
|
|
18
|
+
import shutil
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
from typing import Literal, Self
|
|
21
|
+
|
|
22
|
+
from rclone import Crypt
|
|
23
|
+
|
|
24
|
+
from absfuyu.core.baseclass import AutoREPRMixin
|
|
25
|
+
from absfuyu.logger import LogLevel, logger
|
|
26
|
+
from absfuyu.util.path import DirectoryBase
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# Class
|
|
30
|
+
# ---------------------------------------------------------------------------
|
|
31
|
+
class RcloneEncryptDecrypt(AutoREPRMixin):
|
|
32
|
+
"""
|
|
33
|
+
Rclone Decrypt/Encrypt Module
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
def __init__(self, crypt: Crypt) -> None:
|
|
37
|
+
"""
|
|
38
|
+
This will encrypt/decrypt with rclone style
|
|
39
|
+
|
|
40
|
+
Parameters
|
|
41
|
+
----------
|
|
42
|
+
crypt : Crypt
|
|
43
|
+
``rclone.Crypt`` object | Encrypt/Decrypt engine
|
|
44
|
+
"""
|
|
45
|
+
self._crypt = crypt
|
|
46
|
+
|
|
47
|
+
@classmethod
|
|
48
|
+
def from_passwd_salt(cls, passwd: str, salt: str | None = None) -> Self:
|
|
49
|
+
"""
|
|
50
|
+
Create Rclone Decrypt/Encrypt object from password and salt
|
|
51
|
+
|
|
52
|
+
Parameters
|
|
53
|
+
----------
|
|
54
|
+
passwd : str
|
|
55
|
+
Custom password
|
|
56
|
+
|
|
57
|
+
salt : str | None, optional
|
|
58
|
+
Custom salt, by default None
|
|
59
|
+
|
|
60
|
+
Returns
|
|
61
|
+
-------
|
|
62
|
+
Self
|
|
63
|
+
Rclone Decrypt/Encrypt object
|
|
64
|
+
"""
|
|
65
|
+
if salt is None:
|
|
66
|
+
crypt: Crypt = Crypt(passwd=passwd)
|
|
67
|
+
else:
|
|
68
|
+
crypt: Crypt = Crypt(passwd=passwd, salt=salt)
|
|
69
|
+
return cls(crypt)
|
|
70
|
+
|
|
71
|
+
# Support
|
|
72
|
+
@staticmethod
|
|
73
|
+
def _directory_validator(path: Path) -> Path:
|
|
74
|
+
"""Validate if directory exists, then return the path"""
|
|
75
|
+
path = Path(path)
|
|
76
|
+
if not path.exists():
|
|
77
|
+
raise ValueError("Path does not exist")
|
|
78
|
+
return path
|
|
79
|
+
|
|
80
|
+
def _modify_name(self, name_to_modify: str, mode: Literal["encrypt", "decrypt"]) -> str:
|
|
81
|
+
if mode == "decrypt":
|
|
82
|
+
return self._crypt.Name.standard_decrypt(name_to_modify)
|
|
83
|
+
if mode == "encrypt":
|
|
84
|
+
return self._crypt.Name.standard_encrypt(name_to_modify)
|
|
85
|
+
|
|
86
|
+
def _decrypt_encrypt_operation(
|
|
87
|
+
self,
|
|
88
|
+
mode: Literal["encrypt", "decrypt"],
|
|
89
|
+
root_dir: Path | str, # type: ignore
|
|
90
|
+
delete_when_complete: bool = False,
|
|
91
|
+
) -> None:
|
|
92
|
+
"""
|
|
93
|
+
Base operation to decrypt, encrypt
|
|
94
|
+
|
|
95
|
+
Parameters
|
|
96
|
+
----------
|
|
97
|
+
mode : Literal["encrypt", "decrypt"]
|
|
98
|
+
Encrypt or decrypt
|
|
99
|
+
|
|
100
|
+
root_dir : Path | str
|
|
101
|
+
Directory location
|
|
102
|
+
|
|
103
|
+
delete_when_complete : bool
|
|
104
|
+
Delete directory when completed, defaults to False
|
|
105
|
+
"""
|
|
106
|
+
|
|
107
|
+
logger.info(f"Begin operation: {mode.title()}")
|
|
108
|
+
root_dir = Path(root_dir)
|
|
109
|
+
FILE_MODE = False
|
|
110
|
+
|
|
111
|
+
# Make Base folder
|
|
112
|
+
if root_dir.is_file():
|
|
113
|
+
# Get name of parent dir and make name
|
|
114
|
+
temp = self._modify_name(root_dir.parent.name, "encrypt" if mode == "decrypt" else "decrypt")
|
|
115
|
+
# Create sub dir
|
|
116
|
+
base_dir = root_dir.parent.joinpath(temp)
|
|
117
|
+
base_dir.mkdir(exist_ok=True, parents=True)
|
|
118
|
+
# Move file to that dir
|
|
119
|
+
new_path = root_dir.rename(base_dir.joinpath(root_dir.name))
|
|
120
|
+
root_dir = base_dir # Make root dir
|
|
121
|
+
FILE_MODE = True
|
|
122
|
+
else:
|
|
123
|
+
root_dir: Path = self._directory_validator(root_dir)
|
|
124
|
+
base_name: str = self._modify_name(root_dir.name, mode=mode)
|
|
125
|
+
base_dir: Path = root_dir.parent.joinpath(base_name)
|
|
126
|
+
base_dir.mkdir(exist_ok=True, parents=True)
|
|
127
|
+
|
|
128
|
+
_ljust: int = 17 # Logger ljust value
|
|
129
|
+
|
|
130
|
+
# Decrypt / Encrypt
|
|
131
|
+
for path in root_dir.glob("**/*"):
|
|
132
|
+
rel_path: Path = path.relative_to(root_dir)
|
|
133
|
+
rel_path_splited: list[str] = str(rel_path).split(os.sep)
|
|
134
|
+
rel_path_modified: list[str] = [self._modify_name(x, mode=mode) for x in rel_path_splited]
|
|
135
|
+
new_path: Path = base_dir.joinpath(*rel_path_modified)
|
|
136
|
+
|
|
137
|
+
if path.is_dir():
|
|
138
|
+
logger.debug(f"{mode.title()}ing Dir:".ljust(_ljust) + f"{path}")
|
|
139
|
+
new_path.mkdir(exist_ok=True, parents=True)
|
|
140
|
+
logger.debug(f"{mode.title()}ed Dir:".ljust(_ljust) + f"{new_path}")
|
|
141
|
+
else:
|
|
142
|
+
logger.debug(f"{mode.title()}ing File:".ljust(_ljust) + f"{path}")
|
|
143
|
+
if mode == "decrypt":
|
|
144
|
+
self._crypt.File.file_decrypt(path, new_path) # type: ignore
|
|
145
|
+
if mode == "encrypt":
|
|
146
|
+
self._crypt.File.file_encrypt(path, new_path) # type: ignore
|
|
147
|
+
logger.debug(f"{mode.title()}ed File:".ljust(_ljust) + f"{new_path}")
|
|
148
|
+
logger.info(f"Operation: {mode.title()} COMPLETED")
|
|
149
|
+
|
|
150
|
+
# File mode
|
|
151
|
+
if FILE_MODE:
|
|
152
|
+
new_path.rename(root_dir.parent.joinpath(new_path.name)) # type: ignore
|
|
153
|
+
shutil.rmtree(root_dir)
|
|
154
|
+
|
|
155
|
+
# Delete when completed
|
|
156
|
+
if delete_when_complete:
|
|
157
|
+
logger.debug(f"Deleting {root_dir}")
|
|
158
|
+
shutil.rmtree(root_dir)
|
|
159
|
+
logger.debug(f"Deleting {root_dir}...DONE")
|
|
160
|
+
|
|
161
|
+
# Decrypt/Encrypt
|
|
162
|
+
def decrypt(self, root_dir: Path, delete_when_complete: bool = False) -> None:
|
|
163
|
+
"""
|
|
164
|
+
Decrypt encrypted directory.
|
|
165
|
+
|
|
166
|
+
This will decrypt the directory itself and
|
|
167
|
+
create a decrypted directory next to the original
|
|
168
|
+
|
|
169
|
+
Parameters
|
|
170
|
+
----------
|
|
171
|
+
root_dir : Path
|
|
172
|
+
Directory location
|
|
173
|
+
|
|
174
|
+
delete_when_complete : bool, optional
|
|
175
|
+
Delete directory when completed, by default False
|
|
176
|
+
"""
|
|
177
|
+
self._decrypt_encrypt_operation(mode="decrypt", root_dir=root_dir, delete_when_complete=delete_when_complete)
|
|
178
|
+
|
|
179
|
+
def encrypt(self, root_dir: Path, delete_when_complete: bool = False) -> None:
|
|
180
|
+
"""
|
|
181
|
+
Encrypt entire directory.
|
|
182
|
+
|
|
183
|
+
This will encrypt the directory itself and
|
|
184
|
+
create an encrypted directory next to the original
|
|
185
|
+
|
|
186
|
+
Parameters
|
|
187
|
+
----------
|
|
188
|
+
root_dir : Path
|
|
189
|
+
Directory location
|
|
190
|
+
|
|
191
|
+
delete_when_complete : bool, optional
|
|
192
|
+
Delete directory when completed, by default False
|
|
193
|
+
"""
|
|
194
|
+
self._decrypt_encrypt_operation(mode="encrypt", root_dir=root_dir, delete_when_complete=delete_when_complete)
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
class DirectoryRcloneDEMixin(DirectoryBase):
|
|
198
|
+
"""
|
|
199
|
+
Directory - Rclone encrypt/decrypt
|
|
200
|
+
|
|
201
|
+
Extension for ``absfuyu.util.path.Directory``
|
|
202
|
+
|
|
203
|
+
- Decrypt
|
|
204
|
+
- Encrypt
|
|
205
|
+
"""
|
|
206
|
+
|
|
207
|
+
def rclone_encrypt(self, passwd: str, salt: str | None = None, delete_when_complete: bool = False) -> None:
|
|
208
|
+
"""
|
|
209
|
+
Encrypt entire directory.
|
|
210
|
+
|
|
211
|
+
This will encrypt the directory itself and
|
|
212
|
+
create an encrypted directory next to the original
|
|
213
|
+
|
|
214
|
+
Parameters
|
|
215
|
+
----------
|
|
216
|
+
passwd : str
|
|
217
|
+
Custom password
|
|
218
|
+
|
|
219
|
+
salt : str | None, optional
|
|
220
|
+
Custom salt, by default None
|
|
221
|
+
|
|
222
|
+
delete_when_complete : bool, optional
|
|
223
|
+
Delete directory when completed, by default False
|
|
224
|
+
"""
|
|
225
|
+
engine = RcloneEncryptDecrypt.from_passwd_salt(passwd=passwd, salt=salt)
|
|
226
|
+
engine.encrypt(self.source_path, delete_when_complete=delete_when_complete)
|
|
227
|
+
|
|
228
|
+
def rclone_decrypt(self, passwd: str, salt: str | None = None, delete_when_complete: bool = False) -> None:
|
|
229
|
+
"""
|
|
230
|
+
Decrypt encrypted directory.
|
|
231
|
+
|
|
232
|
+
This will decrypt the directory itself and
|
|
233
|
+
create a decrypted directory next to the original
|
|
234
|
+
|
|
235
|
+
Parameters
|
|
236
|
+
----------
|
|
237
|
+
passwd : str
|
|
238
|
+
Custom password
|
|
239
|
+
|
|
240
|
+
salt : str | None, optional
|
|
241
|
+
Custom salt, by default None
|
|
242
|
+
|
|
243
|
+
delete_when_complete : bool, optional
|
|
244
|
+
Delete directory when completed, by default False
|
|
245
|
+
"""
|
|
246
|
+
engine = RcloneEncryptDecrypt.from_passwd_salt(passwd=passwd, salt=salt)
|
|
247
|
+
engine.decrypt(self.source_path, delete_when_complete=delete_when_complete)
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
# Run
|
|
251
|
+
# -----------------------------------------------------------------------------------------------
|
|
252
|
+
if __name__ == "__main__":
|
|
253
|
+
logger.setLevel(LogLevel.DEBUG)
|