absfuyu 4.1.1__py3-none-any.whl → 5.0.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 +4 -4
- absfuyu/__main__.py +13 -1
- absfuyu/cli/__init__.py +4 -2
- absfuyu/cli/color.py +7 -0
- absfuyu/cli/do_group.py +9 -91
- absfuyu/cli/tool_group.py +136 -0
- absfuyu/config/__init__.py +17 -34
- absfuyu/core/__init__.py +49 -0
- absfuyu/core/baseclass.py +299 -0
- absfuyu/core/baseclass2.py +165 -0
- absfuyu/core/decorator.py +67 -0
- absfuyu/core/docstring.py +163 -0
- absfuyu/core/dummy_cli.py +67 -0
- absfuyu/core/dummy_func.py +47 -0
- absfuyu/dxt/__init__.py +42 -0
- absfuyu/dxt/dictext.py +201 -0
- absfuyu/dxt/dxt_support.py +79 -0
- absfuyu/dxt/intext.py +586 -0
- absfuyu/dxt/listext.py +508 -0
- absfuyu/dxt/strext.py +530 -0
- absfuyu/{extensions → extra}/__init__.py +3 -2
- absfuyu/extra/beautiful.py +251 -0
- absfuyu/{extensions/extra → extra}/data_analysis.py +51 -82
- absfuyu/fun/__init__.py +110 -135
- absfuyu/fun/tarot.py +9 -17
- absfuyu/game/__init__.py +6 -0
- absfuyu/game/game_stat.py +6 -0
- absfuyu/game/sudoku.py +7 -1
- absfuyu/game/tictactoe.py +12 -5
- absfuyu/game/wordle.py +14 -8
- absfuyu/general/__init__.py +6 -79
- absfuyu/general/content.py +22 -36
- absfuyu/general/generator.py +17 -42
- absfuyu/general/human.py +108 -228
- absfuyu/general/shape.py +1334 -0
- absfuyu/logger.py +8 -13
- absfuyu/pkg_data/__init__.py +137 -99
- absfuyu/pkg_data/deprecated.py +133 -0
- absfuyu/pkg_data/passwordlib_lzma.pkl +0 -0
- absfuyu/sort.py +6 -130
- absfuyu/tools/__init__.py +2 -2
- absfuyu/tools/checksum.py +44 -22
- absfuyu/tools/converter.py +82 -50
- absfuyu/tools/keygen.py +25 -30
- absfuyu/tools/obfuscator.py +246 -112
- absfuyu/tools/passwordlib.py +330 -0
- absfuyu/tools/shutdownizer.py +287 -0
- absfuyu/tools/web.py +2 -9
- absfuyu/util/__init__.py +15 -15
- absfuyu/util/api.py +10 -15
- absfuyu/util/json_method.py +7 -24
- absfuyu/util/lunar.py +3 -9
- absfuyu/util/path.py +22 -27
- absfuyu/util/performance.py +43 -67
- absfuyu/util/shorten_number.py +65 -14
- absfuyu/util/zipped.py +9 -15
- absfuyu-5.0.0.dist-info/METADATA +143 -0
- absfuyu-5.0.0.dist-info/RECORD +68 -0
- absfuyu/core.py +0 -57
- absfuyu/everything.py +0 -32
- absfuyu/extensions/beautiful.py +0 -188
- absfuyu/extensions/dev/__init__.py +0 -244
- absfuyu/extensions/dev/password_hash.py +0 -80
- absfuyu/extensions/dev/passwordlib.py +0 -258
- absfuyu/extensions/dev/project_starter.py +0 -60
- absfuyu/extensions/dev/shutdownizer.py +0 -156
- absfuyu/extensions/extra/__init__.py +0 -24
- absfuyu/fun/WGS.py +0 -134
- absfuyu/general/data_extension.py +0 -1796
- absfuyu/tools/stats.py +0 -226
- absfuyu/util/pkl.py +0 -67
- absfuyu-4.1.1.dist-info/METADATA +0 -121
- absfuyu-4.1.1.dist-info/RECORD +0 -61
- {absfuyu-4.1.1.dist-info → absfuyu-5.0.0.dist-info}/WHEEL +0 -0
- {absfuyu-4.1.1.dist-info → absfuyu-5.0.0.dist-info}/entry_points.txt +0 -0
- {absfuyu-4.1.1.dist-info → absfuyu-5.0.0.dist-info}/licenses/LICENSE +0 -0
absfuyu/util/__init__.py
CHANGED
|
@@ -8,15 +8,16 @@ Date updated: 25/11/2024 (dd/mm/yyyy)
|
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
# Library
|
|
11
|
-
|
|
11
|
+
# ---------------------------------------------------------------------------
|
|
12
12
|
import pkgutil
|
|
13
13
|
from datetime import datetime
|
|
14
14
|
|
|
15
|
-
from absfuyu.
|
|
15
|
+
from absfuyu.core import deprecated, versionadded, versionchanged
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
# Function
|
|
19
|
-
|
|
19
|
+
# ---------------------------------------------------------------------------
|
|
20
|
+
@versionchanged("2.7.1", reason="Use ``pkgutil`` lib")
|
|
20
21
|
def get_installed_package():
|
|
21
22
|
"""
|
|
22
23
|
Return a list of installed packages
|
|
@@ -32,6 +33,7 @@ def get_installed_package():
|
|
|
32
33
|
return sorted(iter_modules)
|
|
33
34
|
|
|
34
35
|
|
|
36
|
+
@deprecated("5.0.0")
|
|
35
37
|
def set_min(
|
|
36
38
|
current_value: int | float,
|
|
37
39
|
*,
|
|
@@ -60,11 +62,13 @@ def set_min(
|
|
|
60
62
|
>>> set_min(-1)
|
|
61
63
|
0
|
|
62
64
|
"""
|
|
63
|
-
if current_value < min_value:
|
|
64
|
-
|
|
65
|
-
return current_value
|
|
65
|
+
# if current_value < min_value:
|
|
66
|
+
# current_value = min_value
|
|
67
|
+
# return current_value
|
|
68
|
+
return max(min_value, current_value)
|
|
66
69
|
|
|
67
70
|
|
|
71
|
+
@deprecated("5.0.0")
|
|
68
72
|
def set_max(
|
|
69
73
|
current_value: int | float,
|
|
70
74
|
*,
|
|
@@ -93,9 +97,10 @@ def set_max(
|
|
|
93
97
|
>>> set_max(101)
|
|
94
98
|
100
|
|
95
99
|
"""
|
|
96
|
-
if current_value > max_value:
|
|
97
|
-
|
|
98
|
-
return current_value
|
|
100
|
+
# if current_value > max_value:
|
|
101
|
+
# current_value = max_value
|
|
102
|
+
# return current_value
|
|
103
|
+
return min(max_value, current_value)
|
|
99
104
|
|
|
100
105
|
|
|
101
106
|
def set_min_max(
|
|
@@ -137,6 +142,7 @@ def set_min_max(
|
|
|
137
142
|
return current_value
|
|
138
143
|
|
|
139
144
|
|
|
145
|
+
@versionadded("3.2.0")
|
|
140
146
|
def stop_after_day(
|
|
141
147
|
year: int | None = None, month: int | None = None, day: int | None = None
|
|
142
148
|
) -> None:
|
|
@@ -172,9 +178,3 @@ def stop_after_day(
|
|
|
172
178
|
result = end_date - now
|
|
173
179
|
if result.days < 0:
|
|
174
180
|
raise SystemExit("End of time")
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
# Run
|
|
178
|
-
###########################################################################
|
|
179
|
-
if __name__ == "__main__":
|
|
180
|
-
logger.setLevel(10)
|
absfuyu/util/api.py
CHANGED
|
@@ -3,12 +3,12 @@ Absufyu: API
|
|
|
3
3
|
------------
|
|
4
4
|
Fetch data stuff
|
|
5
5
|
|
|
6
|
-
Version:
|
|
7
|
-
Date updated:
|
|
6
|
+
Version: 5.0.0
|
|
7
|
+
Date updated: 13/02/2025 (dd/mm/yyyy)
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
# Module level
|
|
11
|
-
|
|
11
|
+
# ---------------------------------------------------------------------------
|
|
12
12
|
__all__ = [
|
|
13
13
|
"APIRequest",
|
|
14
14
|
"ping_windows",
|
|
@@ -16,7 +16,7 @@ __all__ = [
|
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
# Library
|
|
19
|
-
|
|
19
|
+
# ---------------------------------------------------------------------------
|
|
20
20
|
import json
|
|
21
21
|
import re
|
|
22
22
|
import subprocess
|
|
@@ -24,13 +24,13 @@ from pathlib import Path
|
|
|
24
24
|
from typing import NamedTuple
|
|
25
25
|
|
|
26
26
|
import requests
|
|
27
|
-
from deprecated.sphinx import versionchanged
|
|
28
27
|
|
|
28
|
+
from absfuyu.core import versionadded, versionchanged
|
|
29
29
|
from absfuyu.logger import logger
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
# Function
|
|
33
|
-
|
|
33
|
+
# ---------------------------------------------------------------------------
|
|
34
34
|
class PingResult(NamedTuple):
|
|
35
35
|
"""
|
|
36
36
|
:param host: Host name/IP
|
|
@@ -41,7 +41,8 @@ class PingResult(NamedTuple):
|
|
|
41
41
|
result: str
|
|
42
42
|
|
|
43
43
|
|
|
44
|
-
@versionchanged(
|
|
44
|
+
@versionchanged("3.4.0", reason="Updated functionality")
|
|
45
|
+
@versionadded("2.5.0")
|
|
45
46
|
def ping_windows(host: list[str], ping_count: int = 3) -> list[PingResult]:
|
|
46
47
|
"""
|
|
47
48
|
Ping web
|
|
@@ -88,7 +89,7 @@ def ping_windows(host: list[str], ping_count: int = 3) -> list[PingResult]:
|
|
|
88
89
|
|
|
89
90
|
|
|
90
91
|
# Class
|
|
91
|
-
|
|
92
|
+
# ---------------------------------------------------------------------------
|
|
92
93
|
class APIRequest:
|
|
93
94
|
"""API data with cache feature"""
|
|
94
95
|
|
|
@@ -143,7 +144,7 @@ class APIRequest:
|
|
|
143
144
|
logger.debug(f"No local cache found... ({e})")
|
|
144
145
|
json_data = None
|
|
145
146
|
|
|
146
|
-
if
|
|
147
|
+
if json_data is None:
|
|
147
148
|
logger.debug("Fetching new json data... (Creating local cache)")
|
|
148
149
|
try:
|
|
149
150
|
json_data = requests.get(self.url).json()
|
|
@@ -164,9 +165,3 @@ class APIRequest:
|
|
|
164
165
|
``requests.Response``
|
|
165
166
|
"""
|
|
166
167
|
return requests.get(self.url)
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
# Run
|
|
170
|
-
###########################################################################
|
|
171
|
-
if __name__ == "__main__":
|
|
172
|
-
logger.setLevel(10)
|
absfuyu/util/json_method.py
CHANGED
|
@@ -3,35 +3,27 @@ Absfuyu: Json Method
|
|
|
3
3
|
--------------------
|
|
4
4
|
``.json`` file handling
|
|
5
5
|
|
|
6
|
-
Version:
|
|
7
|
-
Date updated:
|
|
6
|
+
Version: 5.0.0
|
|
7
|
+
Date updated: 25/02/2025 (dd/mm/yyyy)
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
# Module level
|
|
11
|
-
|
|
11
|
+
# ---------------------------------------------------------------------------
|
|
12
12
|
__all__ = ["JsonFile"]
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
# Library
|
|
16
|
-
|
|
16
|
+
# ---------------------------------------------------------------------------
|
|
17
17
|
import json
|
|
18
18
|
from pathlib import Path
|
|
19
19
|
from typing import Any
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
# Function
|
|
23
|
-
###########################################################################
|
|
24
|
-
def load_json(json_file_location: Path): # Deprecated
|
|
25
|
-
"""Load JSON file"""
|
|
26
|
-
print("This function is deprecated as of version 3.0.0")
|
|
27
|
-
with open(Path(json_file_location), "r") as json_file:
|
|
28
|
-
data = json.load(json_file)
|
|
29
|
-
return data
|
|
21
|
+
from absfuyu.core import BaseClass
|
|
30
22
|
|
|
31
23
|
|
|
32
24
|
# Class
|
|
33
|
-
|
|
34
|
-
class JsonFile:
|
|
25
|
+
# ---------------------------------------------------------------------------
|
|
26
|
+
class JsonFile(BaseClass):
|
|
35
27
|
"""
|
|
36
28
|
``.json`` file handling
|
|
37
29
|
"""
|
|
@@ -59,9 +51,6 @@ class JsonFile:
|
|
|
59
51
|
def __str__(self) -> str:
|
|
60
52
|
return f"{self.__class__.__name__}({self.json_file_location.name})"
|
|
61
53
|
|
|
62
|
-
def __repr__(self) -> str:
|
|
63
|
-
return self.__str__()
|
|
64
|
-
|
|
65
54
|
def load_json(self) -> dict[Any, Any]:
|
|
66
55
|
"""
|
|
67
56
|
Load ``.json`` file
|
|
@@ -87,9 +76,3 @@ class JsonFile:
|
|
|
87
76
|
:type data: dict
|
|
88
77
|
"""
|
|
89
78
|
self.data = data
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
# Run
|
|
93
|
-
###########################################################################
|
|
94
|
-
if __name__ == "__main__":
|
|
95
|
-
pass
|
absfuyu/util/lunar.py
CHANGED
|
@@ -14,18 +14,18 @@ https://www.informatik.uni-leipzig.de/~duc/amlich/AL.py
|
|
|
14
14
|
"""
|
|
15
15
|
|
|
16
16
|
# Module level
|
|
17
|
-
|
|
17
|
+
# ---------------------------------------------------------------------------
|
|
18
18
|
__all__ = ["LunarCalendar"]
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
# Library
|
|
22
|
-
|
|
22
|
+
# ---------------------------------------------------------------------------
|
|
23
23
|
import math
|
|
24
24
|
from datetime import date, datetime
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
# Class
|
|
28
|
-
|
|
28
|
+
# ---------------------------------------------------------------------------
|
|
29
29
|
class LunarCalendar:
|
|
30
30
|
"""Lunar Calendar"""
|
|
31
31
|
|
|
@@ -400,9 +400,3 @@ class LunarCalendar:
|
|
|
400
400
|
"""
|
|
401
401
|
today = datetime.now().date()
|
|
402
402
|
return cls(today.year, today.month, today.day).to_lunar()
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
# Run
|
|
406
|
-
###########################################################################
|
|
407
|
-
if __name__ == "__main__":
|
|
408
|
-
pass
|
absfuyu/util/path.py
CHANGED
|
@@ -3,8 +3,8 @@ Absfuyu: Path
|
|
|
3
3
|
-------------
|
|
4
4
|
Path related
|
|
5
5
|
|
|
6
|
-
Version:
|
|
7
|
-
Date updated:
|
|
6
|
+
Version: 5.0.0
|
|
7
|
+
Date updated: 13/02/2025 (dd/mm/yyyy)
|
|
8
8
|
|
|
9
9
|
Feature:
|
|
10
10
|
--------
|
|
@@ -13,7 +13,7 @@ Feature:
|
|
|
13
13
|
"""
|
|
14
14
|
|
|
15
15
|
# Module level
|
|
16
|
-
|
|
16
|
+
# ---------------------------------------------------------------------------
|
|
17
17
|
__all__ = [
|
|
18
18
|
# Main
|
|
19
19
|
"Directory",
|
|
@@ -25,7 +25,7 @@ __all__ = [
|
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
# Library
|
|
28
|
-
|
|
28
|
+
# ---------------------------------------------------------------------------
|
|
29
29
|
import os
|
|
30
30
|
import re
|
|
31
31
|
import shutil
|
|
@@ -34,14 +34,13 @@ from functools import partial
|
|
|
34
34
|
from pathlib import Path
|
|
35
35
|
from typing import Any, Literal, NamedTuple
|
|
36
36
|
|
|
37
|
-
from
|
|
38
|
-
|
|
39
|
-
from absfuyu.logger import LogLevel, logger
|
|
37
|
+
from absfuyu.core import versionadded
|
|
38
|
+
from absfuyu.logger import logger
|
|
40
39
|
|
|
41
40
|
|
|
42
41
|
# Support Class
|
|
43
|
-
|
|
44
|
-
@versionadded(
|
|
42
|
+
# ---------------------------------------------------------------------------
|
|
43
|
+
@versionadded("3.3.0")
|
|
45
44
|
class FileOrFolderWithModificationTime(NamedTuple):
|
|
46
45
|
"""
|
|
47
46
|
File or Folder with modification time
|
|
@@ -54,9 +53,11 @@ class FileOrFolderWithModificationTime(NamedTuple):
|
|
|
54
53
|
modification_time: datetime
|
|
55
54
|
|
|
56
55
|
|
|
57
|
-
@versionadded(
|
|
56
|
+
@versionadded("3.3.0")
|
|
58
57
|
class DirectoryInfo(NamedTuple):
|
|
59
|
-
"""
|
|
58
|
+
"""
|
|
59
|
+
Information of a directory
|
|
60
|
+
"""
|
|
60
61
|
|
|
61
62
|
files: int
|
|
62
63
|
folders: int
|
|
@@ -65,7 +66,7 @@ class DirectoryInfo(NamedTuple):
|
|
|
65
66
|
|
|
66
67
|
|
|
67
68
|
# Class - Directory | version 3.4.0: Remake Directory into modular class
|
|
68
|
-
|
|
69
|
+
# ---------------------------------------------------------------------------
|
|
69
70
|
class DirectoryBase:
|
|
70
71
|
def __init__(
|
|
71
72
|
self,
|
|
@@ -113,21 +114,21 @@ class DirectoryBase:
|
|
|
113
114
|
|
|
114
115
|
# Everything
|
|
115
116
|
@property
|
|
116
|
-
@versionadded(
|
|
117
|
+
@versionadded("3.3.0")
|
|
117
118
|
def everything(self) -> list[Path]:
|
|
118
119
|
"""
|
|
119
120
|
Every folders and files in this Directory
|
|
120
121
|
"""
|
|
121
122
|
return list(x for x in self.source_path.glob("**/*"))
|
|
122
123
|
|
|
123
|
-
@versionadded(
|
|
124
|
+
@versionadded("3.3.0")
|
|
124
125
|
def _every_folder(self) -> list[Path]:
|
|
125
126
|
"""
|
|
126
127
|
Every folders in this Directory
|
|
127
128
|
"""
|
|
128
129
|
return list(x for x in self.source_path.glob("**/*") if x.is_dir())
|
|
129
130
|
|
|
130
|
-
@versionadded(
|
|
131
|
+
@versionadded("3.3.0")
|
|
131
132
|
def _every_file(self) -> list[Path]:
|
|
132
133
|
"""
|
|
133
134
|
Every folders in this Directory
|
|
@@ -135,7 +136,7 @@ class DirectoryBase:
|
|
|
135
136
|
return list(x for x in self.source_path.glob("**/*") if x.is_file())
|
|
136
137
|
|
|
137
138
|
# Quick information
|
|
138
|
-
@versionadded(
|
|
139
|
+
@versionadded("3.3.0")
|
|
139
140
|
def quick_info(self) -> DirectoryInfo:
|
|
140
141
|
"""
|
|
141
142
|
Quick information about this Directory
|
|
@@ -396,7 +397,7 @@ class Directory(DirectoryBasicOperation, DirectoryTree):
|
|
|
396
397
|
]
|
|
397
398
|
|
|
398
399
|
@staticmethod
|
|
399
|
-
@versionadded(
|
|
400
|
+
@versionadded("3.3.0")
|
|
400
401
|
def _split_dir(list_of_path: list[Path]) -> list[list[str]]:
|
|
401
402
|
"""
|
|
402
403
|
Split pathname by ``os.sep``
|
|
@@ -450,9 +451,9 @@ class Directory(DirectoryBasicOperation, DirectoryTree):
|
|
|
450
451
|
Folder structure ready to print
|
|
451
452
|
"""
|
|
452
453
|
# Check for tab and sub-dir symbol
|
|
453
|
-
if
|
|
454
|
+
if tab_symbol is None:
|
|
454
455
|
tab_symbol = "\t"
|
|
455
|
-
if
|
|
456
|
+
if sub_dir_symbol is None:
|
|
456
457
|
sub_dir_symbol = "|-- "
|
|
457
458
|
|
|
458
459
|
temp: list[list[str]] = self._split_dir(list_of_path)
|
|
@@ -504,7 +505,7 @@ class Directory(DirectoryBasicOperation, DirectoryTree):
|
|
|
504
505
|
|
|
505
506
|
|
|
506
507
|
# Class - SaveFileAs
|
|
507
|
-
|
|
508
|
+
# ---------------------------------------------------------------------------
|
|
508
509
|
class SaveFileAs:
|
|
509
510
|
"""File as multiple file type"""
|
|
510
511
|
|
|
@@ -554,12 +555,6 @@ class SaveFileAs:
|
|
|
554
555
|
|
|
555
556
|
|
|
556
557
|
# Dev and Test new feature before get added to the main class
|
|
557
|
-
|
|
558
|
+
# ---------------------------------------------------------------------------
|
|
558
559
|
class _NewDirFeature(Directory):
|
|
559
560
|
pass
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
# Run
|
|
563
|
-
###########################################################################
|
|
564
|
-
if __name__ == "__main__":
|
|
565
|
-
logger.setLevel(LogLevel.DEBUG)
|
absfuyu/util/performance.py
CHANGED
|
@@ -3,8 +3,8 @@ Absfuyu: Performance
|
|
|
3
3
|
--------------------
|
|
4
4
|
Performance Check
|
|
5
5
|
|
|
6
|
-
Version:
|
|
7
|
-
Date updated:
|
|
6
|
+
Version: 5.0.0
|
|
7
|
+
Date updated: 13/02/2025 (dd/mm/yyyy)
|
|
8
8
|
|
|
9
9
|
Feature:
|
|
10
10
|
--------
|
|
@@ -16,7 +16,7 @@ Feature:
|
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
18
|
# Module level
|
|
19
|
-
|
|
19
|
+
# ---------------------------------------------------------------------------
|
|
20
20
|
__all__ = [
|
|
21
21
|
# Wrapper
|
|
22
22
|
"function_debug",
|
|
@@ -28,36 +28,39 @@ __all__ = [
|
|
|
28
28
|
|
|
29
29
|
|
|
30
30
|
# Library
|
|
31
|
-
|
|
31
|
+
# ---------------------------------------------------------------------------
|
|
32
32
|
import time
|
|
33
33
|
import tracemalloc
|
|
34
|
+
from collections.abc import Callable
|
|
34
35
|
from functools import wraps
|
|
35
36
|
from inspect import getsource
|
|
36
|
-
from typing import Any,
|
|
37
|
+
from typing import Any, ParamSpec, TypeVar
|
|
37
38
|
|
|
38
|
-
from
|
|
39
|
+
from absfuyu.core import versionadded, versionchanged
|
|
40
|
+
from absfuyu.dxt import ListNoDunder
|
|
39
41
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
# Type
|
|
43
|
+
# ---------------------------------------------------------------------------
|
|
44
|
+
P = ParamSpec("P") # Parameter type
|
|
45
|
+
R = TypeVar("R") # Return type
|
|
43
46
|
|
|
44
47
|
|
|
45
48
|
# Function
|
|
46
|
-
|
|
47
|
-
@versionchanged(
|
|
48
|
-
def measure_performance(
|
|
49
|
+
# ---------------------------------------------------------------------------
|
|
50
|
+
@versionchanged("3.2.0", reason="Updated functionality")
|
|
51
|
+
def measure_performance(f: Callable[P, R]) -> Callable[P, R]:
|
|
49
52
|
r"""
|
|
50
53
|
Measure performance of a function
|
|
51
54
|
|
|
52
55
|
Parameters
|
|
53
56
|
----------
|
|
54
|
-
|
|
55
|
-
|
|
57
|
+
f : Callable [P, R]
|
|
58
|
+
Function to measure
|
|
56
59
|
|
|
57
60
|
Returns
|
|
58
61
|
-------
|
|
59
62
|
Callable
|
|
60
|
-
A
|
|
63
|
+
A decorated function
|
|
61
64
|
|
|
62
65
|
|
|
63
66
|
Usage
|
|
@@ -76,14 +79,15 @@ def measure_performance(func: Callable) -> Callable: # type: ignore
|
|
|
76
79
|
Peak memory usage: 0.000000 MB
|
|
77
80
|
Time elapsed (seconds): 0.000002
|
|
78
81
|
--------------------------------------
|
|
82
|
+
|
|
79
83
|
"""
|
|
80
84
|
|
|
81
|
-
@wraps(
|
|
82
|
-
def wrapper(*args, **kwargs) ->
|
|
85
|
+
@wraps(f)
|
|
86
|
+
def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
|
|
83
87
|
# Performance check
|
|
84
88
|
tracemalloc.start() # Start memory measure
|
|
85
89
|
start_time = time.perf_counter() # Start time measure
|
|
86
|
-
output =
|
|
90
|
+
output = f(*args, **kwargs) # Run function and save result into a variable
|
|
87
91
|
current, peak = tracemalloc.get_traced_memory() # Get memory stats
|
|
88
92
|
finish_time = time.perf_counter() # Get finished time
|
|
89
93
|
tracemalloc.stop() # End memory measure
|
|
@@ -91,7 +95,7 @@ def measure_performance(func: Callable) -> Callable: # type: ignore
|
|
|
91
95
|
# Print output
|
|
92
96
|
print(
|
|
93
97
|
f"{'-' * 38}\n"
|
|
94
|
-
f"Function: {
|
|
98
|
+
f"Function: {f.__name__}\n"
|
|
95
99
|
f"Memory usage:\t\t {current / 10**6:,.6f} MB\n"
|
|
96
100
|
f"Peak memory usage:\t {peak / 10**6:,.6f} MB\n"
|
|
97
101
|
f"Time elapsed (seconds):\t {finish_time - start_time:,.6f}\n"
|
|
@@ -104,20 +108,20 @@ def measure_performance(func: Callable) -> Callable: # type: ignore
|
|
|
104
108
|
return wrapper
|
|
105
109
|
|
|
106
110
|
|
|
107
|
-
@versionadded(
|
|
108
|
-
def function_debug(
|
|
111
|
+
@versionadded("3.2.0")
|
|
112
|
+
def function_debug(f: Callable[P, R]) -> Callable[P, R]:
|
|
109
113
|
"""
|
|
110
114
|
Print the function signature and return value
|
|
111
115
|
|
|
112
116
|
Parameters
|
|
113
117
|
----------
|
|
114
118
|
func : Callable
|
|
115
|
-
|
|
119
|
+
Function to debug
|
|
116
120
|
|
|
117
121
|
Returns
|
|
118
122
|
-------
|
|
119
123
|
Callable
|
|
120
|
-
A
|
|
124
|
+
A decorated function
|
|
121
125
|
|
|
122
126
|
|
|
123
127
|
Usage
|
|
@@ -134,26 +138,26 @@ def function_debug(func: Callable) -> Callable: # type: ignore
|
|
|
134
138
|
test() returned 14
|
|
135
139
|
"""
|
|
136
140
|
|
|
137
|
-
@wraps(
|
|
138
|
-
def wrapper(*args, **kwargs) ->
|
|
141
|
+
@wraps(f)
|
|
142
|
+
def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
|
|
139
143
|
# Get all parameters inputed
|
|
140
144
|
args_repr = [repr(a) for a in args]
|
|
141
145
|
kwargs_repr = [f"{k}={repr(v)}" for k, v in kwargs.items()]
|
|
142
146
|
signature = ", ".join(args_repr + kwargs_repr)
|
|
143
147
|
|
|
144
148
|
# Output
|
|
145
|
-
print(f"Calling {
|
|
149
|
+
print(f"Calling {f.__name__}({signature})")
|
|
146
150
|
# logger.debug(f"Calling {func.__name__}({signature})")
|
|
147
|
-
value =
|
|
148
|
-
print(f"{
|
|
151
|
+
value = f(*args, **kwargs)
|
|
152
|
+
print(f"{f.__name__}() returned {repr(value)}")
|
|
149
153
|
# logger.debug(f"{func.__name__}() returned {repr(value)}")
|
|
150
154
|
return value
|
|
151
155
|
|
|
152
156
|
return wrapper
|
|
153
157
|
|
|
154
158
|
|
|
155
|
-
@versionadded(
|
|
156
|
-
def retry(retries: int
|
|
159
|
+
@versionadded("3.2.0")
|
|
160
|
+
def retry(retries: int, delay: float = 1):
|
|
157
161
|
"""
|
|
158
162
|
Attempt to call a function, if it fails, try again with a specified delay.
|
|
159
163
|
|
|
@@ -168,7 +172,7 @@ def retry(retries: int = 3, delay: float = 1) -> Callable: # type: ignore
|
|
|
168
172
|
Returns
|
|
169
173
|
-------
|
|
170
174
|
Callable
|
|
171
|
-
A
|
|
175
|
+
A decorated function
|
|
172
176
|
|
|
173
177
|
|
|
174
178
|
Usage
|
|
@@ -195,18 +199,18 @@ def retry(retries: int = 3, delay: float = 1) -> Callable: # type: ignore
|
|
|
195
199
|
if retries < 1 or delay <= 0:
|
|
196
200
|
raise ValueError("retries must be >= 1, delay must be >= 0")
|
|
197
201
|
|
|
198
|
-
def decorator(
|
|
199
|
-
@wraps(
|
|
200
|
-
def wrapper(*args, **kwargs)
|
|
202
|
+
def decorator(f: Callable[P, R]) -> Callable[P, R]:
|
|
203
|
+
@wraps(f)
|
|
204
|
+
def wrapper(*args: P.args, **kwargs: P.kwargs):
|
|
201
205
|
for i in range(1, retries + 1):
|
|
202
206
|
try:
|
|
203
|
-
print(f"Running ({i}): {
|
|
204
|
-
return
|
|
207
|
+
print(f"Running ({i}): {f.__name__}()")
|
|
208
|
+
return f(*args, **kwargs)
|
|
205
209
|
except Exception as e:
|
|
206
210
|
# Break out of the loop if the max amount of retries is exceeded
|
|
207
211
|
if i == retries:
|
|
208
212
|
print(f"Error: {repr(e)}.")
|
|
209
|
-
print(f'"{
|
|
213
|
+
print(f'"{f.__name__}()" failed after {retries} retries.')
|
|
210
214
|
break
|
|
211
215
|
else:
|
|
212
216
|
print(f"Error: {repr(e)} -> Retrying...")
|
|
@@ -219,31 +223,9 @@ def retry(retries: int = 3, delay: float = 1) -> Callable: # type: ignore
|
|
|
219
223
|
return decorator
|
|
220
224
|
|
|
221
225
|
|
|
222
|
-
def _deprecated_warning(func: Callable): # type: ignore
|
|
223
|
-
"""
|
|
224
|
-
Notice that the function is deprecated and should not be used
|
|
225
|
-
|
|
226
|
-
Parameters
|
|
227
|
-
----------
|
|
228
|
-
func : Callable
|
|
229
|
-
A callable function
|
|
230
|
-
|
|
231
|
-
Usage
|
|
232
|
-
-----
|
|
233
|
-
Use this as the decorator (``@deprecated_warning``)
|
|
234
|
-
"""
|
|
235
|
-
|
|
236
|
-
@wraps(func)
|
|
237
|
-
def wrapper(*args, **kwargs) -> Any:
|
|
238
|
-
print(f"[WARNING] {func.__name__}() is deprecated")
|
|
239
|
-
value = func(*args, **kwargs)
|
|
240
|
-
return value
|
|
241
|
-
|
|
242
|
-
return wrapper
|
|
243
|
-
|
|
244
|
-
|
|
245
226
|
# Class
|
|
246
|
-
|
|
227
|
+
# ---------------------------------------------------------------------------
|
|
228
|
+
# TODO: Rewrite this with inspect
|
|
247
229
|
class Checker:
|
|
248
230
|
"""
|
|
249
231
|
Check a variable
|
|
@@ -339,9 +321,3 @@ class Checker:
|
|
|
339
321
|
out["docs"] = self.docstring
|
|
340
322
|
out["source"] = self.source
|
|
341
323
|
return out
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
# Run
|
|
345
|
-
###########################################################################
|
|
346
|
-
if __name__ == "__main__":
|
|
347
|
-
pass
|