absfuyu 5.0.0__py3-none-any.whl → 6.1.2__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 +5 -3
- absfuyu/__main__.py +3 -3
- absfuyu/cli/__init__.py +13 -2
- absfuyu/cli/audio_group.py +98 -0
- absfuyu/cli/color.py +30 -14
- absfuyu/cli/config_group.py +9 -2
- absfuyu/cli/do_group.py +23 -6
- absfuyu/cli/game_group.py +27 -2
- absfuyu/cli/tool_group.py +81 -11
- absfuyu/config/__init__.py +3 -3
- absfuyu/core/__init__.py +12 -8
- absfuyu/core/baseclass.py +929 -96
- absfuyu/core/baseclass2.py +44 -3
- absfuyu/core/decorator.py +70 -4
- absfuyu/core/docstring.py +64 -41
- absfuyu/core/dummy_cli.py +3 -3
- absfuyu/core/dummy_func.py +19 -6
- absfuyu/dxt/__init__.py +2 -2
- absfuyu/dxt/base_type.py +93 -0
- absfuyu/dxt/dictext.py +204 -16
- absfuyu/dxt/dxt_support.py +2 -2
- absfuyu/dxt/intext.py +151 -34
- absfuyu/dxt/listext.py +969 -127
- absfuyu/dxt/strext.py +77 -17
- absfuyu/extra/__init__.py +2 -2
- absfuyu/extra/audio/__init__.py +8 -0
- absfuyu/extra/audio/_util.py +57 -0
- absfuyu/extra/audio/convert.py +192 -0
- absfuyu/extra/audio/lossless.py +281 -0
- absfuyu/extra/beautiful.py +3 -2
- absfuyu/extra/da/__init__.py +72 -0
- absfuyu/extra/da/dadf.py +1600 -0
- absfuyu/extra/da/dadf_base.py +186 -0
- absfuyu/extra/da/df_func.py +181 -0
- absfuyu/extra/da/mplt.py +219 -0
- absfuyu/extra/ggapi/__init__.py +8 -0
- absfuyu/extra/ggapi/gdrive.py +223 -0
- absfuyu/extra/ggapi/glicense.py +148 -0
- absfuyu/extra/ggapi/glicense_df.py +186 -0
- absfuyu/extra/ggapi/gsheet.py +88 -0
- absfuyu/extra/img/__init__.py +30 -0
- absfuyu/extra/img/converter.py +402 -0
- absfuyu/extra/img/dup_check.py +291 -0
- absfuyu/extra/pdf.py +87 -0
- absfuyu/extra/rclone.py +253 -0
- absfuyu/extra/xml.py +90 -0
- absfuyu/fun/__init__.py +7 -20
- absfuyu/fun/rubik.py +442 -0
- absfuyu/fun/tarot.py +2 -2
- absfuyu/game/__init__.py +2 -2
- absfuyu/game/game_stat.py +2 -2
- absfuyu/game/schulte.py +78 -0
- absfuyu/game/sudoku.py +2 -2
- absfuyu/game/tictactoe.py +2 -3
- absfuyu/game/wordle.py +6 -4
- absfuyu/general/__init__.py +4 -4
- absfuyu/general/content.py +4 -4
- absfuyu/general/human.py +2 -2
- absfuyu/general/resrel.py +213 -0
- absfuyu/general/shape.py +3 -8
- absfuyu/general/tax.py +344 -0
- absfuyu/logger.py +806 -59
- absfuyu/numbers/__init__.py +13 -0
- absfuyu/numbers/number_to_word.py +321 -0
- absfuyu/numbers/shorten_number.py +303 -0
- absfuyu/numbers/time_duration.py +217 -0
- absfuyu/pkg_data/__init__.py +2 -2
- absfuyu/pkg_data/deprecated.py +2 -2
- absfuyu/pkg_data/logo.py +1462 -0
- absfuyu/sort.py +4 -4
- absfuyu/tools/__init__.py +28 -2
- absfuyu/tools/checksum.py +144 -9
- absfuyu/tools/converter.py +120 -34
- absfuyu/tools/generator.py +461 -0
- absfuyu/tools/inspector.py +752 -0
- absfuyu/tools/keygen.py +2 -2
- absfuyu/tools/obfuscator.py +47 -9
- absfuyu/tools/passwordlib.py +89 -25
- absfuyu/tools/shutdownizer.py +3 -8
- absfuyu/tools/sw.py +718 -0
- absfuyu/tools/web.py +10 -13
- absfuyu/typings.py +138 -0
- absfuyu/util/__init__.py +114 -6
- absfuyu/util/api.py +41 -18
- absfuyu/util/cli.py +119 -0
- absfuyu/util/gui.py +91 -0
- absfuyu/util/json_method.py +43 -14
- absfuyu/util/lunar.py +2 -2
- absfuyu/util/package.py +124 -0
- absfuyu/util/path.py +702 -82
- absfuyu/util/performance.py +122 -7
- absfuyu/util/shorten_number.py +244 -21
- absfuyu/util/text_table.py +481 -0
- absfuyu/util/zipped.py +8 -7
- absfuyu/version.py +79 -59
- {absfuyu-5.0.0.dist-info → absfuyu-6.1.2.dist-info}/METADATA +52 -11
- absfuyu-6.1.2.dist-info/RECORD +105 -0
- {absfuyu-5.0.0.dist-info → absfuyu-6.1.2.dist-info}/WHEEL +1 -1
- absfuyu/extra/data_analysis.py +0 -1078
- absfuyu/general/generator.py +0 -303
- absfuyu-5.0.0.dist-info/RECORD +0 -68
- {absfuyu-5.0.0.dist-info → absfuyu-6.1.2.dist-info}/entry_points.txt +0 -0
- {absfuyu-5.0.0.dist-info → absfuyu-6.1.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,752 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Absfuyu: Inspector
|
|
3
|
+
------------------
|
|
4
|
+
Inspector
|
|
5
|
+
|
|
6
|
+
Version: 6.1.1
|
|
7
|
+
Date updated: 30/12/2025 (dd/mm/yyyy)
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
# Module level
|
|
11
|
+
# ---------------------------------------------------------------------------
|
|
12
|
+
__all__ = ["Inspector", "inspect_all"]
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# Library
|
|
16
|
+
# ---------------------------------------------------------------------------
|
|
17
|
+
import inspect as _inspect
|
|
18
|
+
import os
|
|
19
|
+
from collections.abc import Callable
|
|
20
|
+
from dataclasses import dataclass
|
|
21
|
+
from functools import partial
|
|
22
|
+
from textwrap import TextWrapper
|
|
23
|
+
from textwrap import shorten as text_shorten
|
|
24
|
+
from typing import Any, Literal, Protocol, get_overloads, overload
|
|
25
|
+
|
|
26
|
+
from absfuyu.core.baseclass import (
|
|
27
|
+
AutoREPRMixin,
|
|
28
|
+
BaseDataclass,
|
|
29
|
+
ClassMembers,
|
|
30
|
+
ClassMembersResult,
|
|
31
|
+
GetClassMembersMixin,
|
|
32
|
+
)
|
|
33
|
+
from absfuyu.dxt.listext import ListExt
|
|
34
|
+
from absfuyu.typings import P, R
|
|
35
|
+
from absfuyu.util.text_table import BoxStyle, OneColumnTableMaker
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
# TODO: rewrite with each class for docs, method, property, attr, param, title
|
|
39
|
+
# Dataclass
|
|
40
|
+
# ---------------------------------------------------------------------------
|
|
41
|
+
@dataclass
|
|
42
|
+
class BaseDCInspect(BaseDataclass):
|
|
43
|
+
def _make_repr(self) -> str | None:
|
|
44
|
+
fields = self._get_fields()
|
|
45
|
+
if 0 < len(fields) < 2:
|
|
46
|
+
return repr(getattr(self, fields[0]))
|
|
47
|
+
return None
|
|
48
|
+
|
|
49
|
+
def _long_list_terminal_size(
|
|
50
|
+
self, long_list: list[str], width: int = 80, /
|
|
51
|
+
) -> list[str]:
|
|
52
|
+
ll = ListExt(long_list).wrap_to_column(width, margin=4, transpose=True)
|
|
53
|
+
return list(ll)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@dataclass
|
|
57
|
+
class _TitleSignature:
|
|
58
|
+
"""
|
|
59
|
+
Inspector:
|
|
60
|
+
Object's title and signature
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
title: str
|
|
64
|
+
signature: list[str]
|
|
65
|
+
|
|
66
|
+
def make_output(self):
|
|
67
|
+
pass
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@dataclass
|
|
71
|
+
class _Docstring(BaseDCInspect):
|
|
72
|
+
"""
|
|
73
|
+
Inspector:
|
|
74
|
+
Object's docstring
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
docs: str
|
|
78
|
+
|
|
79
|
+
def __repr__(self) -> str:
|
|
80
|
+
r = self._make_repr()
|
|
81
|
+
if r is not None:
|
|
82
|
+
return r
|
|
83
|
+
return super().__repr__()
|
|
84
|
+
|
|
85
|
+
def _get_first_paragraph(self) -> str:
|
|
86
|
+
# Get docs and get first paragraph
|
|
87
|
+
doc_lines = []
|
|
88
|
+
for line in self.docs.splitlines():
|
|
89
|
+
if len(line) < 1:
|
|
90
|
+
break
|
|
91
|
+
doc_lines.append(line.strip())
|
|
92
|
+
return " ".join(doc_lines)
|
|
93
|
+
|
|
94
|
+
def make_output(self) -> list[str]:
|
|
95
|
+
if len(self._get_first_paragraph()) > 0:
|
|
96
|
+
return ["Docstring:", self._get_first_paragraph()]
|
|
97
|
+
return [""]
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
@dataclass
|
|
101
|
+
class _MRO(BaseDCInspect):
|
|
102
|
+
"""
|
|
103
|
+
Inspector:
|
|
104
|
+
Object's MRO, bases
|
|
105
|
+
"""
|
|
106
|
+
|
|
107
|
+
mro: tuple[type, ...]
|
|
108
|
+
|
|
109
|
+
def __repr__(self) -> str:
|
|
110
|
+
r = self._make_repr()
|
|
111
|
+
if r is not None:
|
|
112
|
+
return r
|
|
113
|
+
return super().__repr__()
|
|
114
|
+
|
|
115
|
+
def _make_output(self) -> list[str]:
|
|
116
|
+
out = [
|
|
117
|
+
f"- {i:02}. {x.__module__}.{x.__name__}"
|
|
118
|
+
for i, x in enumerate(self.mro[1:], start=1)
|
|
119
|
+
]
|
|
120
|
+
# ListExt.wrap_to_column
|
|
121
|
+
return out
|
|
122
|
+
|
|
123
|
+
def make_output(self, *, width: int = 80) -> list[str]:
|
|
124
|
+
out = self._make_output()
|
|
125
|
+
if len(out) > 0:
|
|
126
|
+
out_ = self._long_list_terminal_size(out, width)
|
|
127
|
+
return ["", f"Bases (Len: {len(out)}):", *out_]
|
|
128
|
+
return [""]
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
@dataclass
|
|
132
|
+
class _Member(BaseDCInspect):
|
|
133
|
+
"""
|
|
134
|
+
Inspector:
|
|
135
|
+
Object's member
|
|
136
|
+
"""
|
|
137
|
+
|
|
138
|
+
member: ClassMembers
|
|
139
|
+
|
|
140
|
+
def __repr__(self) -> str:
|
|
141
|
+
r = self._make_repr()
|
|
142
|
+
if r is not None:
|
|
143
|
+
return r
|
|
144
|
+
return super().__repr__()
|
|
145
|
+
|
|
146
|
+
def make_output(
|
|
147
|
+
self,
|
|
148
|
+
*,
|
|
149
|
+
width: int = 80,
|
|
150
|
+
obj,
|
|
151
|
+
include_method: bool = True,
|
|
152
|
+
include_property: bool = True,
|
|
153
|
+
) -> list[str]:
|
|
154
|
+
mems = self.member.pack().sort()
|
|
155
|
+
body: list[str] = []
|
|
156
|
+
|
|
157
|
+
if include_method:
|
|
158
|
+
ml = [text_shorten(f"- {x}", width - 4) for x in mems.methods]
|
|
159
|
+
if len(ml) > 0:
|
|
160
|
+
head = ["", f"Methods (Len: {len(ml)}):"]
|
|
161
|
+
head.extend(self._long_list_terminal_size(ml, width))
|
|
162
|
+
body.extend(head)
|
|
163
|
+
|
|
164
|
+
if include_property:
|
|
165
|
+
pl = [
|
|
166
|
+
text_shorten(f"- {x} = {getattr(obj, x, None)}", width - 4)
|
|
167
|
+
for x in mems.properties
|
|
168
|
+
]
|
|
169
|
+
if len(pl) > 0:
|
|
170
|
+
head = ["", f"Properties (Len: {len(pl)}):"]
|
|
171
|
+
head.extend(self._long_list_terminal_size(pl, width))
|
|
172
|
+
body.extend(head)
|
|
173
|
+
|
|
174
|
+
if len(body) > 0:
|
|
175
|
+
return body
|
|
176
|
+
return [""]
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
class InspectComponents(Protocol):
|
|
180
|
+
"""Supports make_output() -> list[str]"""
|
|
181
|
+
|
|
182
|
+
@overload
|
|
183
|
+
def make_output(self) -> list[str]: ...
|
|
184
|
+
@overload
|
|
185
|
+
def make_output(self, *, width: int = ...) -> list[str]: ...
|
|
186
|
+
def make_output(self, *args, **kwargs) -> list[str]: ...
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
# Class
|
|
190
|
+
# ---------------------------------------------------------------------------
|
|
191
|
+
class Inspector(AutoREPRMixin):
|
|
192
|
+
"""
|
|
193
|
+
Inspect an object.
|
|
194
|
+
By default shows object's docstring and attribute (if any).
|
|
195
|
+
|
|
196
|
+
Parameters
|
|
197
|
+
----------
|
|
198
|
+
obj : Any
|
|
199
|
+
Object to inspect
|
|
200
|
+
|
|
201
|
+
line_length: int | None
|
|
202
|
+
Number of cols in inspect output (Split line every line_length).
|
|
203
|
+
Set to ``None`` to use ``os.get_terminal_size()``, by default ``None``
|
|
204
|
+
|
|
205
|
+
include_docs : bool, optional
|
|
206
|
+
Include docstring, by default ``True``
|
|
207
|
+
|
|
208
|
+
include_mro : bool, optional
|
|
209
|
+
Include class bases (__mro__), by default ``False``
|
|
210
|
+
|
|
211
|
+
include_method : bool, optional
|
|
212
|
+
Include object's methods (if any), by default ``False``
|
|
213
|
+
|
|
214
|
+
include_property : bool, optional
|
|
215
|
+
Include object's properties (if any), by default ``False``
|
|
216
|
+
|
|
217
|
+
include_attribute : bool, optional
|
|
218
|
+
Include object's attributes (if any), by default ``True``
|
|
219
|
+
|
|
220
|
+
include_private : bool, optional
|
|
221
|
+
Include object's private attributes, by default ``False``
|
|
222
|
+
|
|
223
|
+
include_all : bool, optional
|
|
224
|
+
Include all infomation availble, by default ``False``
|
|
225
|
+
|
|
226
|
+
max_textwrap_lines : int, optional
|
|
227
|
+
Maximum lines for the output's header (class, signature, repr).
|
|
228
|
+
Must be >= 1, by default ``8``
|
|
229
|
+
|
|
230
|
+
style : BoxStyle, optional
|
|
231
|
+
Style for the table, by default ``"normal"``
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
Example:
|
|
235
|
+
--------
|
|
236
|
+
>>> print(Inspector(<object>, **kwargs))
|
|
237
|
+
"""
|
|
238
|
+
|
|
239
|
+
@overload
|
|
240
|
+
def __init__(self, obj: Any) -> None: ...
|
|
241
|
+
|
|
242
|
+
@overload
|
|
243
|
+
def __init__(self, obj: Any, *, include_all: Literal[True] = ...) -> None: ...
|
|
244
|
+
|
|
245
|
+
@overload
|
|
246
|
+
def __init__(
|
|
247
|
+
self,
|
|
248
|
+
obj: Any,
|
|
249
|
+
*,
|
|
250
|
+
line_length: int | None = None,
|
|
251
|
+
include_docs: bool = True,
|
|
252
|
+
include_mro: bool = False,
|
|
253
|
+
include_method: bool = False,
|
|
254
|
+
include_property: bool = False,
|
|
255
|
+
include_attribute: bool = True,
|
|
256
|
+
include_private: bool = False,
|
|
257
|
+
max_textwrap_lines: int = 8,
|
|
258
|
+
style: BoxStyle = "normal",
|
|
259
|
+
) -> None: ...
|
|
260
|
+
|
|
261
|
+
def __init__(
|
|
262
|
+
self,
|
|
263
|
+
obj: Any,
|
|
264
|
+
*,
|
|
265
|
+
# Line length
|
|
266
|
+
line_length: int | None = None,
|
|
267
|
+
line_length_offset: int = 0, # line_length += line_length_offset (when line_length=None)
|
|
268
|
+
max_textwrap_lines: int = 8,
|
|
269
|
+
# Include
|
|
270
|
+
include_docs: bool = True,
|
|
271
|
+
include_mro: bool = False,
|
|
272
|
+
include_method: bool = False,
|
|
273
|
+
include_property: bool = False,
|
|
274
|
+
include_attribute: bool = True,
|
|
275
|
+
include_dunder: bool = False,
|
|
276
|
+
include_private: bool = False,
|
|
277
|
+
include_all: bool = False,
|
|
278
|
+
# Style
|
|
279
|
+
style: BoxStyle = "normal",
|
|
280
|
+
) -> None:
|
|
281
|
+
"""
|
|
282
|
+
Inspect an object.
|
|
283
|
+
By default shows object's docstring and attribute (if any).
|
|
284
|
+
|
|
285
|
+
Parameters
|
|
286
|
+
----------
|
|
287
|
+
obj : Any
|
|
288
|
+
Object to inspect
|
|
289
|
+
|
|
290
|
+
line_length: int | None
|
|
291
|
+
Number of cols in inspect output (Split line every line_length).
|
|
292
|
+
Set to ``None`` to use ``os.get_terminal_size()``, by default ``None``
|
|
293
|
+
|
|
294
|
+
include_docs : bool, optional
|
|
295
|
+
Include docstring, by default ``True``
|
|
296
|
+
|
|
297
|
+
include_mro : bool, optional
|
|
298
|
+
Include class bases (__mro__), by default ``False``
|
|
299
|
+
|
|
300
|
+
include_method : bool, optional
|
|
301
|
+
Include object's methods (if any), by default ``False``
|
|
302
|
+
|
|
303
|
+
include_property : bool, optional
|
|
304
|
+
Include object's properties (if any), by default ``False``
|
|
305
|
+
|
|
306
|
+
include_attribute : bool, optional
|
|
307
|
+
Include object's attributes (if any), by default ``True``
|
|
308
|
+
|
|
309
|
+
include_private : bool, optional
|
|
310
|
+
Include object's private attributes, by default ``False``
|
|
311
|
+
|
|
312
|
+
include_all : bool, optional
|
|
313
|
+
Include all infomation availble, by default ``False``
|
|
314
|
+
|
|
315
|
+
max_textwrap_lines : int, optional
|
|
316
|
+
Maximum lines for the output's header (class, signature, repr).
|
|
317
|
+
Must be >= 1, by default ``8``
|
|
318
|
+
|
|
319
|
+
style : BoxStyle | Literal["normal", "bold", "dashed", "double", "rounded", ...], optional
|
|
320
|
+
Style for the table, by default ``"normal"``
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
Example:
|
|
324
|
+
--------
|
|
325
|
+
>>> print(Inspector(<object>, **kwargs))
|
|
326
|
+
"""
|
|
327
|
+
self.obj = obj
|
|
328
|
+
self.include_docs = include_docs
|
|
329
|
+
self.include_mro = include_mro
|
|
330
|
+
self.include_method = include_method
|
|
331
|
+
self.include_property = include_property
|
|
332
|
+
self.include_attribute = include_attribute
|
|
333
|
+
self.include_private = include_private
|
|
334
|
+
self.include_dunder = include_dunder
|
|
335
|
+
self._style = style
|
|
336
|
+
|
|
337
|
+
if include_all:
|
|
338
|
+
self.include_docs = True
|
|
339
|
+
self.include_mro = True
|
|
340
|
+
self.include_method = True
|
|
341
|
+
self.include_property = True
|
|
342
|
+
self.include_attribute = True
|
|
343
|
+
self.include_private = True
|
|
344
|
+
|
|
345
|
+
# Setup line length
|
|
346
|
+
if line_length is None:
|
|
347
|
+
try:
|
|
348
|
+
self._linelength = os.get_terminal_size().columns + line_length_offset
|
|
349
|
+
except OSError:
|
|
350
|
+
self._linelength = 88
|
|
351
|
+
elif isinstance(line_length, (int, float)):
|
|
352
|
+
self._linelength = max(int(line_length), 9)
|
|
353
|
+
else:
|
|
354
|
+
raise ValueError("Use different line_length")
|
|
355
|
+
|
|
356
|
+
# Textwrap
|
|
357
|
+
self._text_wrapper = TextWrapper(
|
|
358
|
+
width=self._linelength - 4,
|
|
359
|
+
initial_indent="",
|
|
360
|
+
subsequent_indent="",
|
|
361
|
+
tabsize=4,
|
|
362
|
+
break_long_words=True,
|
|
363
|
+
max_lines=max(max_textwrap_lines, 1),
|
|
364
|
+
)
|
|
365
|
+
|
|
366
|
+
# Output
|
|
367
|
+
self._inspect_output = self._make_output()
|
|
368
|
+
|
|
369
|
+
def __str__(self) -> str:
|
|
370
|
+
return self._inspect_output.make_table()
|
|
371
|
+
|
|
372
|
+
# 00. Support
|
|
373
|
+
# -----------------------------------------------------------
|
|
374
|
+
# @deprecated
|
|
375
|
+
def _long_list_terminal_size(self, long_list: list) -> list:
|
|
376
|
+
ll = ListExt(long_list).wrap_to_column(
|
|
377
|
+
self._linelength, margin=4, transpose=True
|
|
378
|
+
)
|
|
379
|
+
return list(ll)
|
|
380
|
+
|
|
381
|
+
# 01. Signature
|
|
382
|
+
# -----------------------------------------------------------
|
|
383
|
+
def _make_title(self) -> str:
|
|
384
|
+
title_str = (
|
|
385
|
+
str(self.obj)
|
|
386
|
+
if (
|
|
387
|
+
_inspect.isclass(self.obj)
|
|
388
|
+
or callable(self.obj)
|
|
389
|
+
or _inspect.ismodule(self.obj)
|
|
390
|
+
)
|
|
391
|
+
else str(type(self.obj))
|
|
392
|
+
)
|
|
393
|
+
return title_str
|
|
394
|
+
|
|
395
|
+
def _get_signature_prefix(self) -> str:
|
|
396
|
+
# signature prefix
|
|
397
|
+
if _inspect.isclass(self.obj):
|
|
398
|
+
return "class"
|
|
399
|
+
elif _inspect.iscoroutinefunction(self.obj):
|
|
400
|
+
return "async def"
|
|
401
|
+
elif _inspect.isfunction(self.obj):
|
|
402
|
+
return "def"
|
|
403
|
+
return ""
|
|
404
|
+
|
|
405
|
+
# @deprecated
|
|
406
|
+
def get_parameters(self) -> list[str] | None:
|
|
407
|
+
try:
|
|
408
|
+
sig = _inspect.signature(self.obj)
|
|
409
|
+
except (ValueError, AttributeError, TypeError):
|
|
410
|
+
return None
|
|
411
|
+
return [str(x) for x in sig.parameters.values()]
|
|
412
|
+
|
|
413
|
+
def _get_func_signature(self, func: Callable[P, R]) -> list[str]:
|
|
414
|
+
overloads = list(get_overloads(func))
|
|
415
|
+
if len(overloads) < 1:
|
|
416
|
+
return [
|
|
417
|
+
f"{self._get_signature_prefix()} {func.__name__}{_inspect.signature(func)}"
|
|
418
|
+
]
|
|
419
|
+
return [
|
|
420
|
+
f"{self._get_signature_prefix()} {x.__name__}{_inspect.signature(x)}"
|
|
421
|
+
for x in overloads
|
|
422
|
+
]
|
|
423
|
+
|
|
424
|
+
# @deprecated
|
|
425
|
+
def _make_signature(self) -> list[str]:
|
|
426
|
+
try:
|
|
427
|
+
# if isinstance(self.obj, Callable):
|
|
428
|
+
if _inspect.isfunction(self.obj):
|
|
429
|
+
funcs = [
|
|
430
|
+
self._text_wrapper.wrap(x)
|
|
431
|
+
for x in self._get_func_signature(self.obj)
|
|
432
|
+
]
|
|
433
|
+
return ListExt(funcs).flatten()
|
|
434
|
+
return self._text_wrapper.wrap(
|
|
435
|
+
f"{self._get_signature_prefix()} {self.obj.__name__}{_inspect.signature(self.obj)}"
|
|
436
|
+
)
|
|
437
|
+
# not class, func | not type | is module
|
|
438
|
+
except (ValueError, AttributeError, TypeError):
|
|
439
|
+
return self._text_wrapper.wrap(repr(self.obj))
|
|
440
|
+
|
|
441
|
+
@property
|
|
442
|
+
def obj_signature(self) -> _TitleSignature:
|
|
443
|
+
"""Object's title and signature"""
|
|
444
|
+
title: str = self._make_title()
|
|
445
|
+
sig: list[str] = []
|
|
446
|
+
try:
|
|
447
|
+
if _inspect.isfunction(self.obj):
|
|
448
|
+
sig.extend(self._get_func_signature(self.obj))
|
|
449
|
+
sig.append(
|
|
450
|
+
f"{self._get_signature_prefix()} {self.obj.__name__}{_inspect.signature(self.obj)}"
|
|
451
|
+
)
|
|
452
|
+
# not class, func | not type | is module
|
|
453
|
+
except (ValueError, AttributeError, TypeError):
|
|
454
|
+
sig.append(repr(self.obj))
|
|
455
|
+
|
|
456
|
+
return _TitleSignature(title=title, signature=sig)
|
|
457
|
+
|
|
458
|
+
# 02. Docstring
|
|
459
|
+
# -----------------------------------------------------------
|
|
460
|
+
@property
|
|
461
|
+
def obj_docs(self) -> _Docstring:
|
|
462
|
+
"""Object's docstring"""
|
|
463
|
+
docs: str | None = _inspect.getdoc(self.obj)
|
|
464
|
+
|
|
465
|
+
if docs is None:
|
|
466
|
+
return _Docstring("")
|
|
467
|
+
return _Docstring(docs=docs)
|
|
468
|
+
|
|
469
|
+
# @deprecated
|
|
470
|
+
def _get_docs(self) -> str:
|
|
471
|
+
docs: str | None = _inspect.getdoc(self.obj)
|
|
472
|
+
|
|
473
|
+
if docs is None:
|
|
474
|
+
return ""
|
|
475
|
+
|
|
476
|
+
# Get docs and get first paragraph
|
|
477
|
+
# doc_lines: list[str] = [x.strip() for x in docs.splitlines()]
|
|
478
|
+
doc_lines = []
|
|
479
|
+
for line in docs.splitlines():
|
|
480
|
+
if len(line) < 1:
|
|
481
|
+
break
|
|
482
|
+
doc_lines.append(line.strip())
|
|
483
|
+
|
|
484
|
+
return text_shorten(" ".join(doc_lines), width=self._linelength - 4, tabsize=4)
|
|
485
|
+
|
|
486
|
+
# 03. MRO/Bases
|
|
487
|
+
# -----------------------------------------------------------
|
|
488
|
+
@property
|
|
489
|
+
def obj_mro(self) -> _MRO:
|
|
490
|
+
"""Object's MRO, bases"""
|
|
491
|
+
if isinstance(self.obj, type):
|
|
492
|
+
return _MRO(mro=self.obj.__mro__[::-1])
|
|
493
|
+
return _MRO(mro=type(self.obj).__mro__[::-1])
|
|
494
|
+
|
|
495
|
+
@property
|
|
496
|
+
def obj_bases(self) -> _MRO:
|
|
497
|
+
"""Object's MRO, bases"""
|
|
498
|
+
return self.obj_mro
|
|
499
|
+
|
|
500
|
+
# @deprecated
|
|
501
|
+
def _get_mro(self) -> tuple[type, ...]:
|
|
502
|
+
"""Get MRO in reverse and subtract <class 'object'>"""
|
|
503
|
+
if isinstance(self.obj, type):
|
|
504
|
+
return self.obj.__mro__[::-1][1:]
|
|
505
|
+
return type(self.obj).__mro__[::-1][1:]
|
|
506
|
+
|
|
507
|
+
# @deprecated
|
|
508
|
+
def _make_mro_data(self) -> list[str]:
|
|
509
|
+
mro = [
|
|
510
|
+
f"- {i:02}. {x.__module__}.{x.__name__}"
|
|
511
|
+
for i, x in enumerate(self._get_mro(), start=1)
|
|
512
|
+
]
|
|
513
|
+
mod_chunk = self._long_list_terminal_size(mro)
|
|
514
|
+
|
|
515
|
+
# return [text_shorten(x, self._linelength - 4) for x in mod_chunk]
|
|
516
|
+
return mod_chunk
|
|
517
|
+
|
|
518
|
+
# 04. Class's members
|
|
519
|
+
# -----------------------------------------------------------
|
|
520
|
+
def _get_obj_member(self) -> ClassMembersResult:
|
|
521
|
+
# if _inspect.isclass(self.obj) or inspect.ismodule(self.obj):
|
|
522
|
+
if _inspect.isclass(self.obj):
|
|
523
|
+
tmpcls = type(
|
|
524
|
+
"tmpcls",
|
|
525
|
+
(
|
|
526
|
+
self.obj,
|
|
527
|
+
GetClassMembersMixin,
|
|
528
|
+
),
|
|
529
|
+
{},
|
|
530
|
+
)
|
|
531
|
+
else:
|
|
532
|
+
tmpcls = type(
|
|
533
|
+
"tmpcls",
|
|
534
|
+
(
|
|
535
|
+
type(self.obj),
|
|
536
|
+
GetClassMembersMixin,
|
|
537
|
+
),
|
|
538
|
+
{},
|
|
539
|
+
)
|
|
540
|
+
med_prop = tmpcls._get_members( # type: ignore
|
|
541
|
+
dunder=False, private=self.include_private
|
|
542
|
+
)
|
|
543
|
+
|
|
544
|
+
try:
|
|
545
|
+
# If self.obj is a subclass of GetClassMembersMixin
|
|
546
|
+
_mro = getattr(
|
|
547
|
+
self.obj, "__mro__", getattr(type(self.obj), "__mro__", None)
|
|
548
|
+
)
|
|
549
|
+
if GetClassMembersMixin in _mro: # type: ignore
|
|
550
|
+
return med_prop # type: ignore
|
|
551
|
+
except AttributeError: # Not a class
|
|
552
|
+
pass
|
|
553
|
+
med_prop.__delitem__(GetClassMembersMixin.__name__)
|
|
554
|
+
return med_prop # type: ignore
|
|
555
|
+
|
|
556
|
+
@property
|
|
557
|
+
def obj_member(self) -> _Member:
|
|
558
|
+
"""Object's members"""
|
|
559
|
+
try:
|
|
560
|
+
mem = self._get_obj_member()
|
|
561
|
+
return _Member(mem.flatten_value())
|
|
562
|
+
except (TypeError, AttributeError):
|
|
563
|
+
return _Member(ClassMembers())
|
|
564
|
+
|
|
565
|
+
# @deprecated
|
|
566
|
+
def _get_method_property(self) -> ClassMembersResult:
|
|
567
|
+
return self._get_obj_member()
|
|
568
|
+
|
|
569
|
+
# Attribute
|
|
570
|
+
@staticmethod
|
|
571
|
+
def _is_real_attribute(obj: Any) -> bool:
|
|
572
|
+
"""
|
|
573
|
+
Not method, classmethod, staticmethod, property
|
|
574
|
+
"""
|
|
575
|
+
if callable(obj):
|
|
576
|
+
return False
|
|
577
|
+
if isinstance(obj, staticmethod):
|
|
578
|
+
return False
|
|
579
|
+
if isinstance(obj, classmethod):
|
|
580
|
+
return False
|
|
581
|
+
if isinstance(obj, property):
|
|
582
|
+
return False
|
|
583
|
+
return True
|
|
584
|
+
|
|
585
|
+
def _get_attributes(self) -> list[tuple[str, Any]]:
|
|
586
|
+
# Get attributes
|
|
587
|
+
cls_dict = getattr(self.obj, "__dict__", None)
|
|
588
|
+
cls_slots = getattr(self.obj, "__slots__", None)
|
|
589
|
+
out = []
|
|
590
|
+
|
|
591
|
+
# Check if __dict__ exist and len(__dict__) > 0
|
|
592
|
+
if cls_dict is not None and len(cls_dict) > 0:
|
|
593
|
+
if self.include_private:
|
|
594
|
+
out = [
|
|
595
|
+
(k, v)
|
|
596
|
+
for k, v in self.obj.__dict__.items()
|
|
597
|
+
if self._is_real_attribute(v)
|
|
598
|
+
]
|
|
599
|
+
else:
|
|
600
|
+
out = [
|
|
601
|
+
(k, v)
|
|
602
|
+
for k, v in self.obj.__dict__.items()
|
|
603
|
+
if not k.startswith("_") and self._is_real_attribute(v)
|
|
604
|
+
]
|
|
605
|
+
|
|
606
|
+
# Check if __slots__ exist and len(__slots__) > 0
|
|
607
|
+
elif cls_slots is not None and len(cls_slots) > 0:
|
|
608
|
+
if self.include_private:
|
|
609
|
+
out = [
|
|
610
|
+
(x, getattr(self.obj, x))
|
|
611
|
+
for x in self.obj.__slots__ # type: ignore
|
|
612
|
+
if self._is_real_attribute(getattr(self.obj, x))
|
|
613
|
+
]
|
|
614
|
+
else:
|
|
615
|
+
out = [
|
|
616
|
+
(x, getattr(self.obj, x))
|
|
617
|
+
for x in self.obj.__slots__ # type: ignore
|
|
618
|
+
if not x.startswith("_")
|
|
619
|
+
and self._is_real_attribute(getattr(self.obj, x))
|
|
620
|
+
]
|
|
621
|
+
|
|
622
|
+
return out
|
|
623
|
+
|
|
624
|
+
def _handle_attributes_for_output(
|
|
625
|
+
self, attr_list: list[tuple[str, Any]]
|
|
626
|
+
) -> list[str]:
|
|
627
|
+
return [
|
|
628
|
+
text_shorten(f"- {x[0]} = {x[1]}", self._linelength - 4) for x in attr_list
|
|
629
|
+
]
|
|
630
|
+
|
|
631
|
+
# Output
|
|
632
|
+
# -----------------------------------------------------------
|
|
633
|
+
# @deprecated
|
|
634
|
+
def _make_output(self) -> OneColumnTableMaker:
|
|
635
|
+
table = OneColumnTableMaker(self._linelength, style=self._style) # type: ignore
|
|
636
|
+
body: list[str] = []
|
|
637
|
+
|
|
638
|
+
# Signature
|
|
639
|
+
title = self._make_title()
|
|
640
|
+
table.add_title(title)
|
|
641
|
+
sig = self._make_signature()
|
|
642
|
+
if table._title == "": # Title too long
|
|
643
|
+
_title = [title]
|
|
644
|
+
_title.extend(sig)
|
|
645
|
+
table.add_paragraph(_title)
|
|
646
|
+
else:
|
|
647
|
+
table.add_paragraph(sig)
|
|
648
|
+
|
|
649
|
+
# Docstring
|
|
650
|
+
docs = self._get_docs()
|
|
651
|
+
if len(docs) > 0 and self.include_docs:
|
|
652
|
+
body.extend(["Docstring:", docs])
|
|
653
|
+
|
|
654
|
+
# Class bases
|
|
655
|
+
clsbases = self._make_mro_data()
|
|
656
|
+
if len(clsbases) > 0 and self.include_mro:
|
|
657
|
+
body.extend(["", f"Bases (Len: {len(self._get_mro())}):"])
|
|
658
|
+
body.extend(clsbases)
|
|
659
|
+
|
|
660
|
+
# Method & Property
|
|
661
|
+
try:
|
|
662
|
+
method_n_properties = (
|
|
663
|
+
self._get_method_property().flatten_value().pack().sort()
|
|
664
|
+
)
|
|
665
|
+
if self.include_method:
|
|
666
|
+
ml = [
|
|
667
|
+
text_shorten(f"- {x}", self._linelength - 4)
|
|
668
|
+
for x in method_n_properties.methods
|
|
669
|
+
]
|
|
670
|
+
if len(ml) > 0:
|
|
671
|
+
head = ["", f"Methods (Len: {len(ml)}):"]
|
|
672
|
+
head.extend(self._long_list_terminal_size(ml))
|
|
673
|
+
body.extend(head)
|
|
674
|
+
if self.include_property:
|
|
675
|
+
pl = [
|
|
676
|
+
text_shorten(
|
|
677
|
+
f"- {x} = {getattr(self.obj, x, None)}", self._linelength - 4
|
|
678
|
+
)
|
|
679
|
+
for x in method_n_properties.properties
|
|
680
|
+
]
|
|
681
|
+
if len(pl) > 0:
|
|
682
|
+
head = ["", f"Properties (Len: {len(pl)}):"]
|
|
683
|
+
head.extend(pl)
|
|
684
|
+
body.extend(head)
|
|
685
|
+
except (TypeError, AttributeError):
|
|
686
|
+
pass
|
|
687
|
+
|
|
688
|
+
# Attribute
|
|
689
|
+
attrs = self._get_attributes()
|
|
690
|
+
if len(attrs) > 0 and self.include_attribute:
|
|
691
|
+
body.extend(["", f"Attributes (Len: {len(attrs)}):"])
|
|
692
|
+
body.extend(self._handle_attributes_for_output(attr_list=attrs))
|
|
693
|
+
|
|
694
|
+
# Add to table
|
|
695
|
+
table.add_paragraph(body)
|
|
696
|
+
|
|
697
|
+
return table
|
|
698
|
+
|
|
699
|
+
def _make_output_2(self) -> OneColumnTableMaker:
|
|
700
|
+
# Prep
|
|
701
|
+
# components: list[InspectComponents] = [
|
|
702
|
+
# self.obj_signature,
|
|
703
|
+
# self.obj_docs,
|
|
704
|
+
# self.obj_mro,
|
|
705
|
+
# self.obj_member,
|
|
706
|
+
# ]
|
|
707
|
+
table = OneColumnTableMaker(self._linelength, style=self._style) # type: ignore
|
|
708
|
+
body: list[str] = []
|
|
709
|
+
|
|
710
|
+
# Signature
|
|
711
|
+
title = self.obj_signature.title
|
|
712
|
+
table.add_title(title)
|
|
713
|
+
if table._title == "": # Title too long
|
|
714
|
+
_title = [title]
|
|
715
|
+
_title.extend(self.obj_signature.signature)
|
|
716
|
+
table.add_paragraph(_title)
|
|
717
|
+
else:
|
|
718
|
+
table.add_paragraph(self.obj_signature.signature)
|
|
719
|
+
|
|
720
|
+
# Docstring
|
|
721
|
+
if self.include_docs:
|
|
722
|
+
body.extend(self.obj_docs.make_output())
|
|
723
|
+
|
|
724
|
+
# Class bases
|
|
725
|
+
if self.include_mro:
|
|
726
|
+
body.extend(self.obj_mro.make_output(width=self._linelength))
|
|
727
|
+
|
|
728
|
+
# Method & Property
|
|
729
|
+
body.extend(
|
|
730
|
+
self.obj_member.make_output(
|
|
731
|
+
width=self._linelength,
|
|
732
|
+
obj=self.obj,
|
|
733
|
+
include_method=self.include_method,
|
|
734
|
+
include_property=self.include_property,
|
|
735
|
+
)
|
|
736
|
+
)
|
|
737
|
+
|
|
738
|
+
# Attribute
|
|
739
|
+
attrs = self._get_attributes()
|
|
740
|
+
if len(attrs) > 0 and self.include_attribute:
|
|
741
|
+
body.extend(["", f"Attributes (Len: {len(attrs)}):"])
|
|
742
|
+
body.extend(self._handle_attributes_for_output(attr_list=attrs))
|
|
743
|
+
|
|
744
|
+
# Add to table
|
|
745
|
+
table.add_paragraph(body)
|
|
746
|
+
|
|
747
|
+
return table
|
|
748
|
+
|
|
749
|
+
|
|
750
|
+
# Partial
|
|
751
|
+
# ---------------------------------------------------------------------------
|
|
752
|
+
inspect_all = partial(Inspector, line_length=None, include_all=True) # type: ignore
|