absfuyu 4.2.0__py3-none-any.whl → 5.0.1__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 (72) hide show
  1. absfuyu/__init__.py +4 -4
  2. absfuyu/__main__.py +13 -1
  3. absfuyu/cli/__init__.py +2 -2
  4. absfuyu/cli/color.py +9 -2
  5. absfuyu/cli/config_group.py +2 -2
  6. absfuyu/cli/do_group.py +2 -37
  7. absfuyu/cli/game_group.py +2 -2
  8. absfuyu/cli/tool_group.py +7 -7
  9. absfuyu/config/__init__.py +17 -34
  10. absfuyu/core/__init__.py +49 -0
  11. absfuyu/core/baseclass.py +299 -0
  12. absfuyu/core/baseclass2.py +165 -0
  13. absfuyu/core/decorator.py +67 -0
  14. absfuyu/core/docstring.py +166 -0
  15. absfuyu/core/dummy_cli.py +67 -0
  16. absfuyu/core/dummy_func.py +49 -0
  17. absfuyu/dxt/__init__.py +42 -0
  18. absfuyu/dxt/dictext.py +201 -0
  19. absfuyu/dxt/dxt_support.py +79 -0
  20. absfuyu/dxt/intext.py +586 -0
  21. absfuyu/dxt/listext.py +508 -0
  22. absfuyu/dxt/strext.py +530 -0
  23. absfuyu/extra/__init__.py +12 -0
  24. absfuyu/extra/beautiful.py +252 -0
  25. absfuyu/{extensions → extra}/data_analysis.py +51 -82
  26. absfuyu/fun/__init__.py +110 -135
  27. absfuyu/fun/tarot.py +11 -19
  28. absfuyu/game/__init__.py +8 -2
  29. absfuyu/game/game_stat.py +8 -2
  30. absfuyu/game/sudoku.py +9 -3
  31. absfuyu/game/tictactoe.py +14 -7
  32. absfuyu/game/wordle.py +16 -10
  33. absfuyu/general/__init__.py +8 -81
  34. absfuyu/general/content.py +24 -38
  35. absfuyu/general/human.py +108 -228
  36. absfuyu/general/shape.py +1334 -0
  37. absfuyu/logger.py +10 -15
  38. absfuyu/pkg_data/__init__.py +137 -100
  39. absfuyu/pkg_data/deprecated.py +133 -0
  40. absfuyu/sort.py +6 -130
  41. absfuyu/tools/__init__.py +2 -2
  42. absfuyu/tools/checksum.py +33 -22
  43. absfuyu/tools/converter.py +51 -48
  44. absfuyu/{general → tools}/generator.py +17 -42
  45. absfuyu/tools/keygen.py +25 -30
  46. absfuyu/tools/obfuscator.py +246 -112
  47. absfuyu/tools/passwordlib.py +100 -30
  48. absfuyu/tools/shutdownizer.py +68 -47
  49. absfuyu/tools/web.py +4 -11
  50. absfuyu/util/__init__.py +17 -17
  51. absfuyu/util/api.py +10 -15
  52. absfuyu/util/json_method.py +7 -24
  53. absfuyu/util/lunar.py +5 -11
  54. absfuyu/util/path.py +22 -27
  55. absfuyu/util/performance.py +43 -67
  56. absfuyu/util/shorten_number.py +65 -14
  57. absfuyu/util/zipped.py +11 -17
  58. absfuyu/version.py +59 -42
  59. {absfuyu-4.2.0.dist-info → absfuyu-5.0.1.dist-info}/METADATA +41 -14
  60. absfuyu-5.0.1.dist-info/RECORD +68 -0
  61. absfuyu/core.py +0 -57
  62. absfuyu/everything.py +0 -32
  63. absfuyu/extensions/__init__.py +0 -12
  64. absfuyu/extensions/beautiful.py +0 -188
  65. absfuyu/fun/WGS.py +0 -134
  66. absfuyu/general/data_extension.py +0 -1796
  67. absfuyu/tools/stats.py +0 -226
  68. absfuyu/util/pkl.py +0 -67
  69. absfuyu-4.2.0.dist-info/RECORD +0 -59
  70. {absfuyu-4.2.0.dist-info → absfuyu-5.0.1.dist-info}/WHEEL +0 -0
  71. {absfuyu-4.2.0.dist-info → absfuyu-5.0.1.dist-info}/entry_points.txt +0 -0
  72. {absfuyu-4.2.0.dist-info → absfuyu-5.0.1.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,165 @@
1
+ """
2
+ Absfuyu: Core
3
+ -------------
4
+ Bases for other features (with library)
5
+
6
+ Version: 5.0.0
7
+ Date updated: 25/02/2025 (dd/mm/yyyy)
8
+ """
9
+
10
+ # Module Package
11
+ # ---------------------------------------------------------------------------
12
+ __all__ = [
13
+ # Class
14
+ "ShowAllMethodsMixinInspectVer",
15
+ # Metaclass
16
+ "PerformanceTrackingMeta",
17
+ # Class decorator
18
+ "positive_class_init_args",
19
+ ]
20
+
21
+
22
+ # Library
23
+ # ---------------------------------------------------------------------------
24
+ import time
25
+ import tracemalloc
26
+ from collections.abc import Callable
27
+ from functools import wraps
28
+ from inspect import getmro, isfunction
29
+ from types import MethodType
30
+ from typing import Any, ParamSpec, TypeVar
31
+
32
+ # Type
33
+ # ---------------------------------------------------------------------------
34
+ P = ParamSpec("P") # Parameter type
35
+ T = TypeVar("T", bound=type) # Type type - Can be any subtype of `type`
36
+ # R = TypeVar("R") # Return type
37
+
38
+
39
+ # Class
40
+ # ---------------------------------------------------------------------------
41
+ class ShowAllMethodsMixinInspectVer:
42
+ @classmethod
43
+ def show_all_methods(
44
+ cls,
45
+ include_classmethod: bool = True,
46
+ classmethod_indicator: str = "<classmethod>",
47
+ ) -> dict[str, list[str]]:
48
+ result = {}
49
+ for base in getmro(cls)[::-1]:
50
+ methods = []
51
+ # for name, attr in inspect.getmembers(base, predicate=callable):
52
+ for name, attr in base.__dict__.items():
53
+ if name.startswith("__"):
54
+ continue
55
+ if isfunction(attr):
56
+ methods.append(name)
57
+ # if inspect.ismethod(attr):
58
+ if isinstance(attr, (classmethod, MethodType)) and include_classmethod:
59
+ methods.append(f"{name} {classmethod_indicator}")
60
+ if methods:
61
+ result[base.__name__] = sorted(methods)
62
+ return result
63
+
64
+
65
+ # Metaclass
66
+ # ---------------------------------------------------------------------------
67
+ class PerformanceTrackingMeta(type):
68
+ """
69
+ A metaclass that tracks the instantiation time of classes.
70
+
71
+ Usage:
72
+ ------
73
+ >>> class Demo(metaclass=PerformanceTrackingMeta):
74
+ ... def __init__(self):...
75
+ >>> Demo()
76
+ --------------------------------------
77
+ Class: Demo
78
+ Memory usage: 0.000000 MB
79
+ Peak memory usage: 0.000008 MB
80
+ Time elapsed: 0.000001 s
81
+ --------------------------------------
82
+ """
83
+
84
+ def __new__(mcs, name: str, bases: tuple, attrs: dict[str, Any]):
85
+ """
86
+ Intercepts class creation to wrap the ``__init__`` method.
87
+
88
+ Parameters
89
+ ----------
90
+ mcs
91
+ The metaclass
92
+
93
+ name : str
94
+ The class name
95
+
96
+ bases : tuple
97
+ Tuple of base classes
98
+
99
+ attrs : dict[str, Any]
100
+ Dictionary of attributes
101
+ """
102
+ if "__init__" in attrs:
103
+ original_init = attrs["__init__"]
104
+
105
+ @wraps(original_init)
106
+ def wrapped_init(self, *args, **kwargs):
107
+ # Performance check
108
+ tracemalloc.start()
109
+ start_time = time.perf_counter()
110
+
111
+ # Run __init__()
112
+ original_init(self, *args, **kwargs)
113
+
114
+ # Performance stop
115
+ current, peak = tracemalloc.get_traced_memory()
116
+ end_time = time.perf_counter()
117
+ tracemalloc.stop()
118
+ creation_time = end_time - start_time
119
+
120
+ # Print output
121
+ print(
122
+ f"{''.ljust(38, '-')}\n"
123
+ f"Class: {name}\n"
124
+ f"Memory usage:\t\t {current / 10**6:,.6f} MB\n"
125
+ f"Peak memory usage:\t {peak / 10**6:,.6f} MB\n"
126
+ f"Time elapsed:\t\t {creation_time:,.6f} s\n"
127
+ f"{''.ljust(38, '-')}"
128
+ )
129
+
130
+ attrs["__init__"] = wrapped_init
131
+ return super().__new__(mcs, name, bases, attrs)
132
+
133
+
134
+ # Decorator
135
+ # ---------------------------------------------------------------------------
136
+ def positive_class_init_args(cls: T):
137
+ """
138
+ A class decorator that ensures all arguments in the ``__init__()`` method are positive.
139
+ """
140
+ # original_init: Callable[P, None] | None = getattr(cls, "__init__", None)
141
+ # if original_init is None:
142
+ # return cls
143
+ try:
144
+ original_init: Callable[P, None] = cls.__init__ # type: ignore
145
+ except AttributeError:
146
+ return cls
147
+
148
+ @wraps(original_init)
149
+ def new_init(self, *args: P.args, **kwargs: P.kwargs):
150
+ # Check if all positional arguments are positive
151
+ for arg in args:
152
+ if isinstance(arg, (int, float)) and arg < 0:
153
+ raise ValueError(f"Argument {arg} must be positive")
154
+
155
+ # Check if all keyword arguments are positive
156
+ for key, value in kwargs.items():
157
+ if isinstance(value, (int, float)) and value < 0:
158
+ raise ValueError(f"Argument {key}={value} must be positive")
159
+
160
+ # Call the original __init__ method
161
+ original_init(self, *args, **kwargs)
162
+
163
+ # setattr(cls, "__init__", new_init)
164
+ cls.__init__ = new_init # type: ignore
165
+ return cls
@@ -0,0 +1,67 @@
1
+ """
2
+ Absfuyu: Core
3
+ -------------
4
+ Decorator
5
+
6
+ Version: 5.0.0
7
+ Date updated: 22/02/2025 (dd/mm/yyyy)
8
+ """
9
+
10
+ # Module Package
11
+ # ---------------------------------------------------------------------------
12
+ __all__ = ["dummy_decorator", "dummy_decorator_with_args"]
13
+
14
+
15
+ # Library
16
+ # ---------------------------------------------------------------------------
17
+ from collections.abc import Callable
18
+ from functools import wraps
19
+ from typing import ParamSpec, TypeVar, overload
20
+
21
+ # Type
22
+ # ---------------------------------------------------------------------------
23
+ P = ParamSpec("P") # Parameter type
24
+ R = TypeVar("R") # Return type - Can be anything
25
+ T = TypeVar("T", bound=type) # Type type - Can be any subtype of `type`
26
+
27
+
28
+ # Decorator
29
+ # ---------------------------------------------------------------------------
30
+ @overload
31
+ def dummy_decorator(obj: T) -> T: ...
32
+ @overload
33
+ def dummy_decorator(obj: Callable[P, R]) -> Callable[P, R]: ...
34
+ def dummy_decorator(obj: Callable[P, R] | T) -> Callable[P, R] | T:
35
+ """
36
+ This is a decorator that does nothing. Normally used as a placeholder
37
+ """
38
+ if isinstance(obj, type):
39
+ return obj
40
+
41
+ @wraps(obj)
42
+ def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
43
+ return obj(*args, **kwargs)
44
+
45
+ return wrapper
46
+
47
+
48
+ def dummy_decorator_with_args(*args, **kwargs):
49
+ """
50
+ This is a decorator with args and kwargs that does nothing. Normally used as a placeholder
51
+ """
52
+
53
+ @overload
54
+ def decorator(obj: T) -> T: ...
55
+ @overload
56
+ def decorator(obj: Callable[P, R]) -> Callable[P, R]: ...
57
+ def decorator(obj: Callable[P, R] | T) -> Callable[P, R] | T:
58
+ if isinstance(obj, type):
59
+ return obj
60
+
61
+ @wraps(obj)
62
+ def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
63
+ return obj(*args, **kwargs)
64
+
65
+ return wrapper
66
+
67
+ return decorator
@@ -0,0 +1,166 @@
1
+ """
2
+ Absfuyu: Core
3
+ -------------
4
+ Sphinx docstring decorator
5
+
6
+ Version: 5.0.0
7
+ Date updated: 23/02/2025 (dd/mm/yyyy)
8
+ """
9
+
10
+ # Module Package
11
+ # ---------------------------------------------------------------------------
12
+ __all__ = [
13
+ "SphinxDocstring",
14
+ "SphinxDocstringMode",
15
+ "versionadded",
16
+ "versionchanged",
17
+ "deprecated",
18
+ ]
19
+
20
+
21
+ # Library
22
+ # ---------------------------------------------------------------------------
23
+ from collections.abc import Callable
24
+ from enum import Enum
25
+ from functools import partial, wraps
26
+ from string import Template
27
+ from typing import ClassVar, ParamSpec, TypeVar, overload
28
+
29
+ # Type
30
+ # ---------------------------------------------------------------------------
31
+ _P = ParamSpec("_P") # Parameter type
32
+ _R = TypeVar("_R") # Return type - Can be anything
33
+ _T = TypeVar("_T", bound=type) # Type type - Can be any subtype of `type`
34
+
35
+ _SPHINX_DOCS_TEMPLATE = Template("$line_break*$mode in version $version$reason*")
36
+
37
+
38
+ # Class
39
+ # ---------------------------------------------------------------------------
40
+ class SphinxDocstringMode(Enum):
41
+ """
42
+ Enum representing the mode of the version change
43
+ (added, changed, or deprecated)
44
+ """
45
+
46
+ ADDED = "Added"
47
+ CHANGED = "Changed"
48
+ DEPRECATED = "Deprecated"
49
+
50
+
51
+ class SphinxDocstring:
52
+ """
53
+ A class-based decorator to add a 'Version added',
54
+ 'Version changed', or 'Deprecated' note to a function's docstring,
55
+ formatted for Sphinx documentation.
56
+ """
57
+
58
+ _LINEBREAK: ClassVar[str] = "\n\n" # Use ClassVar for constant
59
+
60
+ def __init__(
61
+ self,
62
+ version: str,
63
+ reason: str | None = None,
64
+ mode: SphinxDocstringMode = SphinxDocstringMode.ADDED,
65
+ ) -> None:
66
+ """
67
+ Initializes the SphinxDocstring decorator.
68
+
69
+ Parameters
70
+ ----------
71
+ version : str
72
+ The version in which the function was added, changed, or deprecated.
73
+
74
+ reason : str | None, optional
75
+ An optional reason or description for the change
76
+ or deprecation, by default ``None``
77
+
78
+ mode : SphinxDocstringMode | int, optional
79
+ Specifies whether the function was 'added', 'changed', or 'deprecated',
80
+ by default SphinxDocstringMode.ADDED
81
+
82
+ Usage
83
+ -----
84
+ Use this as a decorator (``@SphinxDocstring(<parameters>)``)
85
+ """
86
+ self.version = version
87
+ self.reason = reason
88
+ self.mode = mode
89
+
90
+ @overload
91
+ def __call__(self, obj: _T) -> _T: ... # Class overload
92
+
93
+ @overload
94
+ def __call__(
95
+ self, obj: Callable[_P, _R]
96
+ ) -> Callable[_P, _R]: ... # Function overload
97
+ def __call__(self, obj: _T | Callable[_P, _R]) -> _T | Callable[_P, _R]:
98
+ # Class wrapper
99
+ if isinstance(obj, type): # if inspect.isclass(obj):
100
+ obj.__doc__ = (obj.__doc__ or "") + self._generate_version_note(
101
+ num_of_white_spaces=self._calculate_white_space(obj.__doc__)
102
+ )
103
+ return obj
104
+
105
+ # Function wrapper
106
+ @wraps(obj)
107
+ def wrapper(*args: _P.args, **kwargs: _P.kwargs) -> _R:
108
+ return obj(*args, **kwargs)
109
+
110
+ # Add docstring
111
+ # version_note = self._generate_version_note()
112
+ # if wrapper.__doc__ is None:
113
+ # wrapper.__doc__ = version_note
114
+ # else:
115
+ # wrapper.__doc__ += version_note
116
+
117
+ wrapper.__doc__ = (wrapper.__doc__ or "") + self._generate_version_note(
118
+ num_of_white_spaces=self._calculate_white_space(wrapper.__doc__)
119
+ )
120
+
121
+ return wrapper
122
+
123
+ def _calculate_white_space(self, docs: str | None) -> int:
124
+ """
125
+ Calculates the number of leading white spaces
126
+ in __doc__ of original function
127
+ """
128
+
129
+ res = 0
130
+ if docs is None:
131
+ return res
132
+
133
+ try:
134
+ # Replace tabs with space and split line
135
+ lines = docs.expandtabs(4).splitlines()
136
+ except UnicodeError:
137
+ return res
138
+ else:
139
+ # Get indentation of each line and unique it
140
+ indent_set = {len(line) - len(line.lstrip()) for line in lines[1:]}
141
+ # Drop 0
142
+ res_list = sorted([x for x in indent_set if x > 0])
143
+
144
+ if res_list:
145
+ return res_list[0]
146
+ return res
147
+
148
+ def _generate_version_note(self, num_of_white_spaces: int) -> str:
149
+ """
150
+ Generates the version note string based on the mode
151
+ """
152
+ reason_str = f": {self.reason}" if self.reason else ""
153
+ # return f"{self._LINEBREAK}*{self.mode.value} in version {self.version}{reason_str}*"
154
+ return _SPHINX_DOCS_TEMPLATE.substitute(
155
+ line_break=self._LINEBREAK + " " * num_of_white_spaces,
156
+ mode=self.mode.value,
157
+ version=self.version,
158
+ reason=reason_str,
159
+ )
160
+
161
+
162
+ # Partial
163
+ # ---------------------------------------------------------------------------
164
+ versionadded = partial(SphinxDocstring, mode=SphinxDocstringMode.ADDED)
165
+ versionchanged = partial(SphinxDocstring, mode=SphinxDocstringMode.CHANGED)
166
+ deprecated = partial(SphinxDocstring, mode=SphinxDocstringMode.DEPRECATED)
@@ -0,0 +1,67 @@
1
+ """
2
+ Absfuyu: Core
3
+ -------------
4
+ Dummy cli
5
+
6
+ Version: 5.0.0
7
+ Date updated: 25/02/2025 (dd/mm/yyyy)
8
+ """
9
+
10
+ # Module Package
11
+ # ---------------------------------------------------------------------------
12
+ __all__ = ["cli"]
13
+
14
+
15
+ # Library
16
+ # ---------------------------------------------------------------------------
17
+ import sys
18
+ from argparse import ArgumentDefaultsHelpFormatter, ArgumentParser
19
+
20
+ from absfuyu import __title__, __version__
21
+
22
+
23
+ # Function
24
+ # ---------------------------------------------------------------------------
25
+ def get_parser(
26
+ name: str | None = None,
27
+ description: str | None = None,
28
+ epilog: str | None = None,
29
+ *,
30
+ version: str = "",
31
+ add_help: bool = True,
32
+ add_logging: bool = True,
33
+ ) -> ArgumentParser:
34
+ arg_parser = ArgumentParser(
35
+ prog=name,
36
+ description=description,
37
+ epilog=epilog,
38
+ add_help=add_help,
39
+ formatter_class=ArgumentDefaultsHelpFormatter,
40
+ # allow_abbrev=False, # Disable long options recognize
41
+ # exit_on_error=True
42
+ )
43
+ arg_parser.add_argument(
44
+ "--version", action="version", version=f"%(prog)s {version}"
45
+ )
46
+ if add_logging:
47
+ _ll_val = ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]
48
+ arg_parser.add_argument(
49
+ "--log-level",
50
+ metavar="LOG_LEVEL",
51
+ dest="log_level",
52
+ choices=_ll_val,
53
+ default="INFO",
54
+ help=f"Log level: {_ll_val}",
55
+ )
56
+ return arg_parser
57
+
58
+
59
+ def cli() -> None:
60
+ desc = "This is a dummy cli, please install <click> and <colorama> package to use this feature"
61
+ arg_parser = get_parser(
62
+ name=__title__,
63
+ description=desc,
64
+ version=__version__,
65
+ add_logging=False,
66
+ )
67
+ args = arg_parser.parse_args(args=None if sys.argv[1:] else ["--help"]) # noqa
@@ -0,0 +1,49 @@
1
+ """
2
+ Absfuyu: Core
3
+ -------------
4
+ Dummy functions when other libraries are unvailable
5
+
6
+ Version: 5.0.0
7
+ Date updated: 22/02/2025 (dd/mm/yyyy)
8
+ """
9
+
10
+ # Module Package
11
+ # ---------------------------------------------------------------------------
12
+ __all__ = [
13
+ "tqdm",
14
+ "unidecode",
15
+ ]
16
+
17
+
18
+ # Library
19
+ # ---------------------------------------------------------------------------
20
+ from importlib import import_module
21
+
22
+ # Wrapper
23
+ # ---------------------------------------------------------------------------
24
+ # tqdm wrapper
25
+ try:
26
+ _tqdm = import_module("tqdm")
27
+ tqdm = getattr(_tqdm, "tqdm") # noqa
28
+ except (ModuleNotFoundError, AttributeError):
29
+
30
+ def tqdm(iterable, *args, **kwargs):
31
+ """
32
+ Dummy tqdm function,
33
+ install package ``tqdm`` to fully use this feature
34
+ """
35
+ return iterable
36
+
37
+
38
+ # unidecode wrapper
39
+ try:
40
+ _unidecode = import_module("unidecode")
41
+ unidecode = getattr(_unidecode, "unidecode") # noqa
42
+ except (ModuleNotFoundError, AttributeError):
43
+
44
+ def unidecode(*args, **kwargs):
45
+ """
46
+ Dummy unidecode function,
47
+ install package ``unidecode`` to fully use this feature
48
+ """
49
+ return args[0]
@@ -0,0 +1,42 @@
1
+ """
2
+ Absfuyu: Data Extension
3
+ -----------------------
4
+ Extension for data type such as ``list``, ``str``, ``dict``, ...
5
+
6
+ Version: 5.0.0
7
+ Date updated: 22/02/2025 (dd/mm/yyyy)
8
+
9
+ Features:
10
+ ---------
11
+ - DictExt
12
+ - IntExt
13
+ - ListExt
14
+ - Text
15
+ """
16
+
17
+ # Module Package
18
+ # ---------------------------------------------------------------------------
19
+ __all__ = [
20
+ # Main
21
+ "DictExt",
22
+ "IntExt",
23
+ "ListExt",
24
+ "Text",
25
+ # Support
26
+ "DictAnalyzeResult",
27
+ "DictBoolFalse",
28
+ "DictBoolTrue",
29
+ "ListNoDunder",
30
+ "ListREPR",
31
+ "Pow",
32
+ "TextAnalyzeDictFormat",
33
+ ]
34
+
35
+
36
+ # Library
37
+ # ---------------------------------------------------------------------------
38
+ from absfuyu.dxt.dictext import DictAnalyzeResult, DictExt
39
+ from absfuyu.dxt.dxt_support import DictBoolFalse, DictBoolTrue, ListNoDunder, ListREPR
40
+ from absfuyu.dxt.intext import IntExt, Pow
41
+ from absfuyu.dxt.listext import ListExt
42
+ from absfuyu.dxt.strext import Text, TextAnalyzeDictFormat