absfuyu 4.2.0__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.

Files changed (67) hide show
  1. absfuyu/__init__.py +4 -4
  2. absfuyu/__main__.py +13 -1
  3. absfuyu/cli/color.py +7 -0
  4. absfuyu/cli/do_group.py +0 -35
  5. absfuyu/cli/tool_group.py +5 -5
  6. absfuyu/config/__init__.py +17 -34
  7. absfuyu/core/__init__.py +49 -0
  8. absfuyu/core/baseclass.py +299 -0
  9. absfuyu/core/baseclass2.py +165 -0
  10. absfuyu/core/decorator.py +67 -0
  11. absfuyu/core/docstring.py +163 -0
  12. absfuyu/core/dummy_cli.py +67 -0
  13. absfuyu/core/dummy_func.py +47 -0
  14. absfuyu/dxt/__init__.py +42 -0
  15. absfuyu/dxt/dictext.py +201 -0
  16. absfuyu/dxt/dxt_support.py +79 -0
  17. absfuyu/dxt/intext.py +586 -0
  18. absfuyu/dxt/listext.py +508 -0
  19. absfuyu/dxt/strext.py +530 -0
  20. absfuyu/{extensions → extra}/__init__.py +2 -2
  21. absfuyu/extra/beautiful.py +251 -0
  22. absfuyu/{extensions → extra}/data_analysis.py +51 -82
  23. absfuyu/fun/__init__.py +110 -135
  24. absfuyu/fun/tarot.py +9 -17
  25. absfuyu/game/__init__.py +6 -0
  26. absfuyu/game/game_stat.py +6 -0
  27. absfuyu/game/sudoku.py +7 -1
  28. absfuyu/game/tictactoe.py +12 -5
  29. absfuyu/game/wordle.py +14 -8
  30. absfuyu/general/__init__.py +6 -79
  31. absfuyu/general/content.py +22 -36
  32. absfuyu/general/generator.py +17 -42
  33. absfuyu/general/human.py +108 -228
  34. absfuyu/general/shape.py +1334 -0
  35. absfuyu/logger.py +8 -13
  36. absfuyu/pkg_data/__init__.py +136 -99
  37. absfuyu/pkg_data/deprecated.py +133 -0
  38. absfuyu/sort.py +6 -130
  39. absfuyu/tools/__init__.py +2 -2
  40. absfuyu/tools/checksum.py +33 -22
  41. absfuyu/tools/converter.py +51 -48
  42. absfuyu/tools/keygen.py +25 -30
  43. absfuyu/tools/obfuscator.py +246 -112
  44. absfuyu/tools/passwordlib.py +99 -29
  45. absfuyu/tools/shutdownizer.py +68 -47
  46. absfuyu/tools/web.py +2 -9
  47. absfuyu/util/__init__.py +15 -15
  48. absfuyu/util/api.py +10 -15
  49. absfuyu/util/json_method.py +7 -24
  50. absfuyu/util/lunar.py +3 -9
  51. absfuyu/util/path.py +22 -27
  52. absfuyu/util/performance.py +43 -67
  53. absfuyu/util/shorten_number.py +65 -14
  54. absfuyu/util/zipped.py +9 -15
  55. {absfuyu-4.2.0.dist-info → absfuyu-5.0.0.dist-info}/METADATA +41 -14
  56. absfuyu-5.0.0.dist-info/RECORD +68 -0
  57. absfuyu/core.py +0 -57
  58. absfuyu/everything.py +0 -32
  59. absfuyu/extensions/beautiful.py +0 -188
  60. absfuyu/fun/WGS.py +0 -134
  61. absfuyu/general/data_extension.py +0 -1796
  62. absfuyu/tools/stats.py +0 -226
  63. absfuyu/util/pkl.py +0 -67
  64. absfuyu-4.2.0.dist-info/RECORD +0 -59
  65. {absfuyu-4.2.0.dist-info → absfuyu-5.0.0.dist-info}/WHEEL +0 -0
  66. {absfuyu-4.2.0.dist-info → absfuyu-5.0.0.dist-info}/entry_points.txt +0 -0
  67. {absfuyu-4.2.0.dist-info → absfuyu-5.0.0.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: 12/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,163 @@
1
+ """
2
+ Absfuyu: Core
3
+ -------------
4
+ Sphinx docstring decorator
5
+
6
+ Version: 5.0.0
7
+ Date updated: 13/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
+ @overload
93
+ def __call__(self, obj: Callable[P, R]) -> Callable[P, R]: ... # Function overload
94
+ def __call__(self, obj: T | Callable[P, R]) -> T | Callable[P, R]:
95
+ # Class wrapper
96
+ if isinstance(obj, type): # if inspect.isclass(obj):
97
+ obj.__doc__ = (obj.__doc__ or "") + self._generate_version_note(
98
+ num_of_white_spaces=self._calculate_white_space(obj.__doc__)
99
+ )
100
+ return obj
101
+
102
+ # Function wrapper
103
+ @wraps(obj)
104
+ def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
105
+ return obj(*args, **kwargs)
106
+
107
+ # Add docstring
108
+ # version_note = self._generate_version_note()
109
+ # if wrapper.__doc__ is None:
110
+ # wrapper.__doc__ = version_note
111
+ # else:
112
+ # wrapper.__doc__ += version_note
113
+
114
+ wrapper.__doc__ = (wrapper.__doc__ or "") + self._generate_version_note(
115
+ num_of_white_spaces=self._calculate_white_space(wrapper.__doc__)
116
+ )
117
+
118
+ return wrapper
119
+
120
+ def _calculate_white_space(self, docs: str | None) -> int:
121
+ """
122
+ Calculates the number of leading white spaces
123
+ in __doc__ of original function
124
+ """
125
+
126
+ res = 0
127
+ if docs is None:
128
+ return res
129
+
130
+ # # Index of the last whitespaces
131
+ # # https://stackoverflow.com/a/13649118
132
+ # res = next((i for i, c in enumerate(docs) if not c.isspace()), 0)
133
+ # return res if res % 2 == 0 else res - 1
134
+
135
+ # Alternative solution
136
+ for char in docs:
137
+ if char == " ":
138
+ res += 1
139
+ if char == "\t":
140
+ res += 4
141
+ if not char.isspace():
142
+ break
143
+ return res
144
+
145
+ def _generate_version_note(self, num_of_white_spaces: int) -> str:
146
+ """
147
+ Generates the version note string based on the mode
148
+ """
149
+ reason_str = f": {self.reason}" if self.reason else ""
150
+ # return f"{self._LINEBREAK}*{self.mode.value} in version {self.version}{reason_str}*"
151
+ return _SPHINX_DOCS_TEMPLATE.substitute(
152
+ line_break=self._LINEBREAK + " " * num_of_white_spaces,
153
+ mode=self.mode.value,
154
+ version=self.version,
155
+ reason=reason_str,
156
+ )
157
+
158
+
159
+ # Partial
160
+ # ---------------------------------------------------------------------------
161
+ versionadded = partial(SphinxDocstring, mode=SphinxDocstringMode.ADDED)
162
+ versionchanged = partial(SphinxDocstring, mode=SphinxDocstringMode.CHANGED)
163
+ 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,47 @@
1
+ """
2
+ Absfuyu: Core
3
+ -------------
4
+ Dummy functions when other libraries are unvailable
5
+
6
+ Version: 5.0.0
7
+ Date updated: 14/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").tqdm
27
+ except ModuleNotFoundError:
28
+
29
+ def tqdm(iterable, *args, **kwargs):
30
+ """
31
+ Dummy tqdm function,
32
+ install package ``tqdm`` to fully use this feature
33
+ """
34
+ return iterable
35
+
36
+
37
+ # unidecode wrapper
38
+ try:
39
+ unidecode = import_module("unidecode").unidecode
40
+ except ModuleNotFoundError:
41
+
42
+ def unidecode(*args, **kwargs):
43
+ """
44
+ Dummy unidecode function,
45
+ install package ``unidecode`` to fully use this feature
46
+ """
47
+ 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: 11/01/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