encommon 0.13.1__py3-none-any.whl → 0.14.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.
- encommon/__init__.py +2 -7
- encommon/colors/__init__.py +14 -0
- encommon/colors/colors.py +518 -0
- encommon/colors/test/__init__.py +6 -0
- encommon/colors/test/test_colors.py +189 -0
- encommon/config/config.py +73 -20
- encommon/config/files.py +3 -0
- encommon/config/logger.py +5 -0
- encommon/config/params.py +1 -2
- encommon/config/paths.py +3 -0
- encommon/config/test/test_config.py +5 -1
- encommon/config/test/test_logger.py +13 -8
- encommon/config/test/test_paths.py +1 -1
- encommon/config/utils.py +7 -1
- encommon/conftest.py +33 -22
- encommon/crypts/params.py +23 -4
- encommon/times/__init__.py +3 -1
- encommon/times/common.py +2 -1
- encommon/times/params.py +38 -8
- encommon/times/parse.py +37 -10
- encommon/times/test/test_parse.py +16 -9
- encommon/times/test/test_times.py +35 -2
- encommon/times/test/test_unitime.py +23 -0
- encommon/times/times.py +71 -13
- encommon/times/unitime.py +48 -0
- encommon/types/__init__.py +20 -2
- encommon/types/classes.py +97 -0
- encommon/types/lists.py +27 -0
- encommon/types/strings.py +29 -4
- encommon/types/test/test_classes.py +74 -0
- encommon/types/test/test_lists.py +23 -0
- encommon/types/test/test_strings.py +15 -3
- encommon/types/types.py +20 -0
- encommon/utils/__init__.py +4 -0
- encommon/utils/paths.py +5 -6
- encommon/utils/sample.py +117 -41
- encommon/utils/stdout.py +51 -5
- encommon/utils/test/test_sample.py +127 -28
- encommon/utils/test/test_stdout.py +91 -27
- encommon/version.txt +1 -1
- {encommon-0.13.1.dist-info → encommon-0.14.0.dist-info}/METADATA +1 -1
- encommon-0.14.0.dist-info/RECORD +84 -0
- {encommon-0.13.1.dist-info → encommon-0.14.0.dist-info}/WHEEL +1 -1
- encommon-0.13.1.dist-info/RECORD +0 -73
- {encommon-0.13.1.dist-info → encommon-0.14.0.dist-info}/LICENSE +0 -0
- {encommon-0.13.1.dist-info → encommon-0.14.0.dist-info}/top_level.txt +0 -0
encommon/types/strings.py
CHANGED
@@ -21,22 +21,24 @@ SPACED = ' '
|
|
21
21
|
|
22
22
|
|
23
23
|
|
24
|
-
def
|
25
|
-
value:
|
24
|
+
def strplwr(
|
25
|
+
value: Any, # noqa: ANN401
|
26
26
|
) -> str:
|
27
27
|
"""
|
28
28
|
Return the provided string but stripped and lower cased.
|
29
29
|
|
30
30
|
Example
|
31
31
|
-------
|
32
|
-
>>>
|
32
|
+
>>> strplwr(' Foo ')
|
33
33
|
'foo'
|
34
34
|
|
35
35
|
:param value: String which will be stripped and lowered.
|
36
36
|
:returns: Provided string but stripped and lower cased.
|
37
37
|
"""
|
38
38
|
|
39
|
-
|
39
|
+
_value = str(value)
|
40
|
+
|
41
|
+
return _value.strip().lower()
|
40
42
|
|
41
43
|
|
42
44
|
|
@@ -108,3 +110,26 @@ def instr(
|
|
108
110
|
"""
|
109
111
|
|
110
112
|
return hasstr(str(haystack), needle)
|
113
|
+
|
114
|
+
|
115
|
+
|
116
|
+
def rplstr(
|
117
|
+
source: str,
|
118
|
+
match: str,
|
119
|
+
value: Any, # noqa: ANN401
|
120
|
+
) -> str:
|
121
|
+
"""
|
122
|
+
Return the source string with the match value replaced.
|
123
|
+
|
124
|
+
:param source: String that to be processed and returned.
|
125
|
+
:param match: What will be replaced within the string.
|
126
|
+
:param value: Replace value for the string is matched.
|
127
|
+
:returns: Source string with the match value replaced.
|
128
|
+
"""
|
129
|
+
|
130
|
+
match = str(match)
|
131
|
+
value = str(value)
|
132
|
+
|
133
|
+
return (
|
134
|
+
str(source)
|
135
|
+
.replace(match, value))
|
@@ -0,0 +1,74 @@
|
|
1
|
+
"""
|
2
|
+
Functions and routines associated with Enasis Network Common Library.
|
3
|
+
|
4
|
+
This file is part of Enasis Network software eco-system. Distribution
|
5
|
+
is permitted, for more information consult the project license file.
|
6
|
+
"""
|
7
|
+
|
8
|
+
|
9
|
+
|
10
|
+
from typing import TYPE_CHECKING
|
11
|
+
|
12
|
+
from ..classes import clsname
|
13
|
+
from ..classes import lattrs
|
14
|
+
from ...config import LoggerParams
|
15
|
+
|
16
|
+
if TYPE_CHECKING:
|
17
|
+
from ...config import Config
|
18
|
+
|
19
|
+
|
20
|
+
|
21
|
+
def test_BaseModel() -> None:
|
22
|
+
"""
|
23
|
+
Perform various tests associated with relevant routines.
|
24
|
+
"""
|
25
|
+
|
26
|
+
params = LoggerParams(
|
27
|
+
stdo_level='info')
|
28
|
+
|
29
|
+
dumped = params.model_dumped
|
30
|
+
pruned = params.model_pruned
|
31
|
+
|
32
|
+
assert dumped == {
|
33
|
+
'file_level': None,
|
34
|
+
'file_path': None,
|
35
|
+
'stdo_level': 'info'}
|
36
|
+
|
37
|
+
assert pruned == {
|
38
|
+
'stdo_level': 'info'}
|
39
|
+
|
40
|
+
|
41
|
+
|
42
|
+
def test_clsname(
|
43
|
+
config: 'Config',
|
44
|
+
) -> None:
|
45
|
+
"""
|
46
|
+
Perform various tests associated with relevant routines.
|
47
|
+
|
48
|
+
:param config: Primary class instance for configuration.
|
49
|
+
"""
|
50
|
+
|
51
|
+
assert clsname(config) == 'Config'
|
52
|
+
|
53
|
+
|
54
|
+
|
55
|
+
def test_lattrs(
|
56
|
+
config: 'Config',
|
57
|
+
) -> None:
|
58
|
+
"""
|
59
|
+
Perform various tests associated with relevant routines.
|
60
|
+
|
61
|
+
:param config: Primary class instance for configuration.
|
62
|
+
"""
|
63
|
+
|
64
|
+
attrs = lattrs(config)
|
65
|
+
|
66
|
+
assert attrs == [
|
67
|
+
'_Config__model',
|
68
|
+
'_Config__files',
|
69
|
+
'_Config__cargs',
|
70
|
+
'_Config__sargs',
|
71
|
+
'_Config__params',
|
72
|
+
'_Config__paths',
|
73
|
+
'_Config__logger',
|
74
|
+
'_Config__crypts']
|
@@ -0,0 +1,23 @@
|
|
1
|
+
"""
|
2
|
+
Functions and routines associated with Enasis Network Common Library.
|
3
|
+
|
4
|
+
This file is part of Enasis Network software eco-system. Distribution
|
5
|
+
is permitted, for more information consult the project license file.
|
6
|
+
"""
|
7
|
+
|
8
|
+
|
9
|
+
|
10
|
+
from ..lists import inlist
|
11
|
+
|
12
|
+
|
13
|
+
|
14
|
+
def test_inlist() -> None:
|
15
|
+
"""
|
16
|
+
Perform various tests associated with relevant routines.
|
17
|
+
"""
|
18
|
+
|
19
|
+
needle = 123
|
20
|
+
|
21
|
+
haystack = [123, 456]
|
22
|
+
|
23
|
+
assert inlist(needle, haystack)
|
@@ -10,16 +10,17 @@ is permitted, for more information consult the project license file.
|
|
10
10
|
from ..strings import hasstr
|
11
11
|
from ..strings import inrepr
|
12
12
|
from ..strings import instr
|
13
|
-
from ..strings import
|
13
|
+
from ..strings import rplstr
|
14
|
+
from ..strings import strplwr
|
14
15
|
|
15
16
|
|
16
17
|
|
17
|
-
def
|
18
|
+
def test_strplwr() -> None:
|
18
19
|
"""
|
19
20
|
Perform various tests associated with relevant routines.
|
20
21
|
"""
|
21
22
|
|
22
|
-
assert
|
23
|
+
assert strplwr(' Foo ') == 'foo'
|
23
24
|
|
24
25
|
|
25
26
|
|
@@ -59,3 +60,14 @@ def test_instr() -> None:
|
|
59
60
|
item = MyClass()
|
60
61
|
|
61
62
|
assert instr('MyClass', item)
|
63
|
+
|
64
|
+
|
65
|
+
|
66
|
+
def test_rplstr() -> None:
|
67
|
+
"""
|
68
|
+
Perform various tests associated with relevant routines.
|
69
|
+
"""
|
70
|
+
|
71
|
+
string = rplstr('foo', 'o', 'O')
|
72
|
+
|
73
|
+
assert string == 'fOO'
|
encommon/types/types.py
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
"""
|
2
|
+
Functions and routines associated with Enasis Network Common Library.
|
3
|
+
|
4
|
+
This file is part of Enasis Network software eco-system. Distribution
|
5
|
+
is permitted, for more information consult the project license file.
|
6
|
+
"""
|
7
|
+
|
8
|
+
|
9
|
+
|
10
|
+
from typing import Any
|
11
|
+
|
12
|
+
|
13
|
+
|
14
|
+
DictStrAny = dict[str, Any]
|
15
|
+
|
16
|
+
|
17
|
+
|
18
|
+
NCTrue = True
|
19
|
+
NCFalse = False
|
20
|
+
NCNone = None
|
encommon/utils/__init__.py
CHANGED
@@ -16,6 +16,8 @@ from .paths import resolve_paths
|
|
16
16
|
from .paths import stats_path
|
17
17
|
from .sample import load_sample
|
18
18
|
from .sample import prep_sample
|
19
|
+
from .sample import read_sample
|
20
|
+
from .sample import rvrt_sample
|
19
21
|
from .stdout import array_ansi
|
20
22
|
from .stdout import kvpair_ansi
|
21
23
|
from .stdout import make_ansi
|
@@ -32,7 +34,9 @@ __all__ = [
|
|
32
34
|
'make_ansi',
|
33
35
|
'prep_sample',
|
34
36
|
'print_ansi',
|
37
|
+
'read_sample',
|
35
38
|
'read_text',
|
39
|
+
'rvrt_sample',
|
36
40
|
'resolve_path',
|
37
41
|
'resolve_paths',
|
38
42
|
'rgxp_match',
|
encommon/utils/paths.py
CHANGED
@@ -13,6 +13,7 @@ from typing import Optional
|
|
13
13
|
from typing import TYPE_CHECKING
|
14
14
|
|
15
15
|
from .match import rgxp_match
|
16
|
+
from ..types import rplstr
|
16
17
|
from ..types import sort_dict
|
17
18
|
|
18
19
|
if TYPE_CHECKING:
|
@@ -50,13 +51,11 @@ def resolve_path(
|
|
50
51
|
|
51
52
|
for old, new in items:
|
52
53
|
|
53
|
-
|
54
|
-
|
54
|
+
old = str(old)
|
55
|
+
new = str(new)
|
55
56
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
path = path.replace(old, new)
|
57
|
+
path = rplstr(
|
58
|
+
path, old, new)
|
60
59
|
|
61
60
|
return Path(path).resolve()
|
62
61
|
|
encommon/utils/sample.py
CHANGED
@@ -7,54 +7,79 @@ is permitted, for more information consult the project license file.
|
|
7
7
|
|
8
8
|
|
9
9
|
|
10
|
+
from dataclasses import asdict
|
11
|
+
from dataclasses import is_dataclass
|
10
12
|
from json import dumps
|
11
|
-
from
|
13
|
+
from os import environ
|
12
14
|
from pathlib import Path
|
13
15
|
from typing import Any
|
14
16
|
from typing import Callable
|
15
17
|
from typing import Optional
|
16
|
-
|
18
|
+
|
19
|
+
from pydantic import BaseModel
|
17
20
|
|
18
21
|
from .files import read_text
|
19
22
|
from .files import save_text
|
23
|
+
from ..types import rplstr
|
24
|
+
|
25
|
+
|
26
|
+
|
27
|
+
PREFIX = 'encommon_sample'
|
20
28
|
|
21
|
-
|
22
|
-
|
29
|
+
ENPYRWS = (
|
30
|
+
environ.get('ENPYRWS') == '1')
|
23
31
|
|
24
32
|
|
25
33
|
|
26
|
-
def prep_sample(
|
34
|
+
def prep_sample( # noqa: CFQ004
|
27
35
|
content: Any,
|
28
36
|
*,
|
29
37
|
default: Callable[[Any], str] = str,
|
30
|
-
replace: Optional[
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
.. testsetup::
|
36
|
-
>>> from ..types import Empty
|
38
|
+
replace: Optional[dict[str, Any]] = None,
|
39
|
+
indent: Optional[int] = 2,
|
40
|
+
) -> str:
|
41
|
+
r"""
|
42
|
+
Return the content after processing as the sample value.
|
37
43
|
|
38
44
|
Example
|
39
45
|
-------
|
40
46
|
>>> prep_sample(['one', 'two'])
|
41
|
-
[
|
47
|
+
'[\n "one",\n "two"\n]'
|
42
48
|
|
43
49
|
Example
|
44
50
|
-------
|
51
|
+
>>> from ..types import Empty
|
45
52
|
>>> prep_sample({'one': Empty})
|
46
|
-
{
|
53
|
+
'{\n "one": "Empty"\n}'
|
47
54
|
|
48
55
|
:param content: Content that will be processed as JSON.
|
49
56
|
:param default: Callable used when stringifying values.
|
50
57
|
:param replace: Optional values to replace in the file.
|
51
|
-
:returns: Content after processing
|
58
|
+
:returns: Content after processing as the sample value.
|
52
59
|
"""
|
53
60
|
|
54
|
-
content = dumps(
|
55
|
-
content, default=default)
|
56
61
|
|
57
|
-
|
62
|
+
def _default(
|
63
|
+
value: Any, # noqa: ANN401
|
64
|
+
) -> dict[str, Any] | str:
|
65
|
+
|
66
|
+
if is_dataclass(value):
|
67
|
+
|
68
|
+
assert not isinstance(
|
69
|
+
value, type)
|
70
|
+
|
71
|
+
return asdict(value)
|
72
|
+
|
73
|
+
if isinstance(value, BaseModel):
|
74
|
+
return value.model_dump()
|
75
|
+
|
76
|
+
return str(value)
|
77
|
+
|
78
|
+
|
79
|
+
content = dumps(
|
80
|
+
content,
|
81
|
+
default=_default,
|
82
|
+
indent=indent)
|
58
83
|
|
59
84
|
replace = replace or {}
|
60
85
|
|
@@ -62,16 +87,14 @@ def prep_sample(
|
|
62
87
|
|
63
88
|
for old, new in items:
|
64
89
|
|
65
|
-
|
66
|
-
old = str(old)
|
90
|
+
new = str(new)
|
67
91
|
|
68
|
-
|
69
|
-
new = str(new)
|
92
|
+
old = f'_/{PREFIX}/{old}/_'
|
70
93
|
|
71
|
-
content =
|
72
|
-
new,
|
94
|
+
content = rplstr(
|
95
|
+
content, new, old)
|
73
96
|
|
74
|
-
return
|
97
|
+
return str(content)
|
75
98
|
|
76
99
|
|
77
100
|
|
@@ -81,9 +104,9 @@ def load_sample(
|
|
81
104
|
update: bool = False,
|
82
105
|
*,
|
83
106
|
default: Callable[[Any], str] = str,
|
84
|
-
replace: Optional[
|
85
|
-
) ->
|
86
|
-
"""
|
107
|
+
replace: Optional[dict[str, Any]] = None,
|
108
|
+
) -> str:
|
109
|
+
r"""
|
87
110
|
Load the sample file and compare using provided content.
|
88
111
|
|
89
112
|
.. testsetup::
|
@@ -96,14 +119,14 @@ def load_sample(
|
|
96
119
|
-------
|
97
120
|
>>> content = {'one': 'two'}
|
98
121
|
>>> load_sample(sample, content)
|
99
|
-
{
|
122
|
+
'{\n "one": "two"\n}'
|
100
123
|
|
101
124
|
Example
|
102
125
|
-------
|
103
126
|
>>> load_sample(sample)
|
104
|
-
{
|
127
|
+
'{\n "one": "two"\n}'
|
105
128
|
|
106
|
-
:param path: Complete or relative path for
|
129
|
+
:param path: Complete or relative path for sample file.
|
107
130
|
:param update: Determine whether the sample is updated.
|
108
131
|
:param content: Content that will be processed as JSON.
|
109
132
|
:param default: Callable used when stringifying values.
|
@@ -111,6 +134,7 @@ def load_sample(
|
|
111
134
|
:returns: Content after processing using JSON functions.
|
112
135
|
"""
|
113
136
|
|
137
|
+
|
114
138
|
path = Path(path).resolve()
|
115
139
|
|
116
140
|
loaded: Optional[Any] = None
|
@@ -123,18 +147,11 @@ def load_sample(
|
|
123
147
|
|
124
148
|
|
125
149
|
def _save_sample() -> None:
|
126
|
-
|
127
|
-
dumped = dumps(
|
128
|
-
content, indent=2)
|
129
|
-
|
130
|
-
save_text(path, dumped)
|
150
|
+
save_text(path, content)
|
131
151
|
|
132
152
|
|
133
|
-
def _load_sample() ->
|
134
|
-
|
135
|
-
loaded = read_text(path)
|
136
|
-
|
137
|
-
return loads(loaded)
|
153
|
+
def _load_sample() -> str:
|
154
|
+
return read_text(path)
|
138
155
|
|
139
156
|
|
140
157
|
if path.exists():
|
@@ -150,3 +167,62 @@ def load_sample(
|
|
150
167
|
|
151
168
|
|
152
169
|
return _load_sample()
|
170
|
+
|
171
|
+
|
172
|
+
|
173
|
+
def read_sample(
|
174
|
+
sample: str,
|
175
|
+
*,
|
176
|
+
replace: Optional[dict[str, Any]] = None,
|
177
|
+
prefix: bool = True,
|
178
|
+
) -> str:
|
179
|
+
"""
|
180
|
+
Return the content after processing as the sample value.
|
181
|
+
|
182
|
+
:param sample: Content that will be processed as sample.
|
183
|
+
:param replace: Optional values to replace in the file.
|
184
|
+
:param prefix: Determine whether or not prefix is added.
|
185
|
+
:returns: Content after processing as the sample value.
|
186
|
+
"""
|
187
|
+
|
188
|
+
replace = replace or {}
|
189
|
+
|
190
|
+
items = replace.items()
|
191
|
+
|
192
|
+
for new, old in items:
|
193
|
+
|
194
|
+
if prefix is True:
|
195
|
+
old = f'_/{PREFIX}/{old}/_'
|
196
|
+
|
197
|
+
sample = rplstr(
|
198
|
+
sample, new, old)
|
199
|
+
|
200
|
+
return str(sample)
|
201
|
+
|
202
|
+
|
203
|
+
|
204
|
+
def rvrt_sample(
|
205
|
+
sample: str,
|
206
|
+
*,
|
207
|
+
replace: Optional[dict[str, Any]] = None,
|
208
|
+
) -> str:
|
209
|
+
"""
|
210
|
+
Return the content after processing as the sample value.
|
211
|
+
|
212
|
+
:param sample: Content that will be processed as sample.
|
213
|
+
:param replace: Optional values to replace in the file.
|
214
|
+
:returns: Content after processing as the sample value.
|
215
|
+
"""
|
216
|
+
|
217
|
+
replace = replace or {}
|
218
|
+
|
219
|
+
items = replace.items()
|
220
|
+
|
221
|
+
for new, old in items:
|
222
|
+
|
223
|
+
new = f'_/{PREFIX}/{new}/_'
|
224
|
+
|
225
|
+
sample = rplstr(
|
226
|
+
sample, new, old)
|
227
|
+
|
228
|
+
return str(sample)
|
encommon/utils/stdout.py
CHANGED
@@ -7,23 +7,32 @@ is permitted, for more information consult the project license file.
|
|
7
7
|
|
8
8
|
|
9
9
|
|
10
|
+
from dataclasses import asdict
|
10
11
|
from dataclasses import dataclass
|
12
|
+
from dataclasses import is_dataclass
|
11
13
|
from re import compile
|
12
14
|
from re import sub as re_sub
|
13
15
|
from sys import stdout
|
14
16
|
from typing import Any
|
15
17
|
from typing import Literal
|
16
18
|
from typing import Optional
|
19
|
+
from typing import TYPE_CHECKING
|
17
20
|
from typing import Union
|
18
21
|
|
22
|
+
from pydantic import BaseModel
|
23
|
+
|
19
24
|
from .common import JOINABLE
|
20
25
|
from ..times import Duration
|
21
26
|
from ..times import Times
|
22
27
|
from ..types import Empty
|
28
|
+
from ..types import clsname
|
23
29
|
from ..types.strings import COMMAD
|
24
30
|
from ..types.strings import NEWLINE
|
25
31
|
from ..types.strings import SEMPTY
|
26
32
|
|
33
|
+
if TYPE_CHECKING:
|
34
|
+
from _typeshed import DataclassInstance
|
35
|
+
|
27
36
|
|
28
37
|
|
29
38
|
ANSICODE = compile(
|
@@ -34,7 +43,10 @@ ANSIARRAL = Union[
|
|
34
43
|
tuple[Any, ...],
|
35
44
|
set[Any]]
|
36
45
|
|
37
|
-
ANSIARRAD =
|
46
|
+
ANSIARRAD = Union[
|
47
|
+
dict[Any, Any],
|
48
|
+
BaseModel,
|
49
|
+
'DataclassInstance']
|
38
50
|
|
39
51
|
ANSIARRAY = Union[
|
40
52
|
ANSIARRAL,
|
@@ -220,14 +232,21 @@ def array_ansi( # noqa: CFQ001, CFQ004
|
|
220
232
|
'list': list,
|
221
233
|
'tuple': tuple,
|
222
234
|
'dict': dict,
|
235
|
+
'BaseModel': BaseModel,
|
223
236
|
'frozenset': frozenset,
|
224
237
|
'set': set}
|
225
238
|
|
226
239
|
items = typing.items()
|
227
240
|
|
228
|
-
for name,
|
241
|
+
for name, typed in items:
|
242
|
+
|
243
|
+
if isinstance(value, BaseModel):
|
244
|
+
name = clsname(value)
|
229
245
|
|
230
|
-
|
246
|
+
elif is_dataclass(value):
|
247
|
+
name = clsname(value)
|
248
|
+
|
249
|
+
elif not isinstance(value, typed):
|
231
250
|
continue
|
232
251
|
|
233
252
|
output.append(
|
@@ -288,6 +307,12 @@ def array_ansi( # noqa: CFQ001, CFQ004
|
|
288
307
|
refers: Optional[set[int]] = None,
|
289
308
|
) -> None:
|
290
309
|
|
310
|
+
if isinstance(source, BaseModel):
|
311
|
+
source = source.model_dump()
|
312
|
+
|
313
|
+
if is_dataclass(source):
|
314
|
+
source = asdict(source)
|
315
|
+
|
291
316
|
assert isinstance(source, dict)
|
292
317
|
|
293
318
|
items = source.items()
|
@@ -325,19 +350,40 @@ def array_ansi( # noqa: CFQ001, CFQ004
|
|
325
350
|
|
326
351
|
|
327
352
|
def _process(
|
328
|
-
source:
|
353
|
+
source: ANSIARRAY,
|
329
354
|
**kwargs: Any,
|
330
355
|
) -> None:
|
331
356
|
|
332
357
|
if isinstance(source, dict):
|
333
358
|
return _dict(source, **kwargs)
|
334
359
|
|
335
|
-
|
360
|
+
if isinstance(source, BaseModel):
|
361
|
+
return _dict(source, **kwargs)
|
362
|
+
|
363
|
+
if is_dataclass(source):
|
364
|
+
return _dict(source, **kwargs)
|
365
|
+
|
366
|
+
assert isinstance(
|
367
|
+
source,
|
368
|
+
set | list | tuple)
|
369
|
+
|
370
|
+
_list(source, **kwargs)
|
371
|
+
|
372
|
+
|
373
|
+
if is_dataclass(source):
|
374
|
+
|
375
|
+
assert not isinstance(
|
376
|
+
source, type)
|
377
|
+
|
378
|
+
source = asdict(source)
|
336
379
|
|
337
380
|
|
338
381
|
if isinstance(source, dict):
|
339
382
|
_dict(source, indent)
|
340
383
|
|
384
|
+
elif isinstance(source, BaseModel):
|
385
|
+
_dict(source, indent)
|
386
|
+
|
341
387
|
elif isinstance(source, list):
|
342
388
|
_list(source, indent)
|
343
389
|
|