encommon 0.6.0__py3-none-any.whl → 0.7.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.
@@ -14,6 +14,7 @@ from .paths import resolve_paths
14
14
  from .paths import stats_path
15
15
  from .sample import load_sample
16
16
  from .sample import prep_sample
17
+ from .stdout import array_ansi
17
18
  from .stdout import kvpair_ansi
18
19
  from .stdout import make_ansi
19
20
  from .stdout import print_ansi
@@ -22,6 +23,7 @@ from .stdout import strip_ansi
22
23
 
23
24
 
24
25
  __all__ = [
26
+ 'array_ansi',
25
27
  'fuzz_match',
26
28
  'kvpair_ansi',
27
29
  'load_sample',
encommon/utils/stdout.py CHANGED
@@ -7,11 +7,18 @@ is permitted, for more information consult the project license file.
7
7
 
8
8
 
9
9
 
10
+ from dataclasses import dataclass
10
11
  from re import compile
11
12
  from re import sub as re_sub
12
13
  from sys import stdout
13
14
  from typing import Any
14
15
  from typing import Literal
16
+ from typing import Optional
17
+ from typing import Union
18
+
19
+ from encommon.times import Duration
20
+ from encommon.times import Times
21
+ from encommon.types import Empty
15
22
 
16
23
  from .common import JOINABLE
17
24
 
@@ -20,6 +27,40 @@ from .common import JOINABLE
20
27
  ANSICODE = compile(
21
28
  r'\x1b\[[^A-Za-z]*[A-Za-z]')
22
29
 
30
+ ANSIARRAL = Union[
31
+ list[Any],
32
+ tuple[Any, ...],
33
+ set[Any]]
34
+
35
+ ANSIARRAD = dict[Any, Any]
36
+
37
+ ANSIARRAY = Union[
38
+ ANSIARRAL,
39
+ ANSIARRAD]
40
+
41
+
42
+
43
+ @dataclass(frozen=True)
44
+ class ArrayColors:
45
+ """
46
+ Colors used to colorize the provided array like object.
47
+ """
48
+
49
+ label: int = 37
50
+ key: int = 97
51
+
52
+ bool: int = 93
53
+ none: int = 33
54
+ str: int = 92
55
+ num: int = 93
56
+
57
+ times: int = 96
58
+ empty: int = 36
59
+ other: int = 91
60
+
61
+ colon: int = 37
62
+ hyphen: int = 37
63
+
23
64
 
24
65
 
25
66
  def print_ansi(
@@ -121,3 +162,174 @@ def strip_ansi(
121
162
  """ # noqa: D301 LIT102
122
163
 
123
164
  return re_sub(ANSICODE, '', string)
165
+
166
+
167
+
168
+ def array_ansi( # noqa: CFQ001, CFQ004
169
+ source: ANSIARRAY,
170
+ *,
171
+ indent: int = 0,
172
+ colors: ArrayColors = ArrayColors(),
173
+ ) -> str:
174
+ """
175
+ Print the ANSI colorized iterable to the standard output.
176
+
177
+ .. note::
178
+ This massive function should be refactored, possibly
179
+ into a class with methods where there are functions.
180
+
181
+ :param source: Value in supported and iterable formats.
182
+ :param indent: How many levels for initial indentation.
183
+ :param colors: Determine colors used with different types.
184
+ :returns: ANSI colorized string using inline directives.
185
+ """
186
+
187
+ output: list[str] = []
188
+
189
+ repeat = f'<c{colors.other}>REPEAT<c0>'
190
+
191
+
192
+ def _append(
193
+ prefix: str,
194
+ value: Any, # noqa: ANN401
195
+ indent: int,
196
+ refers: set[int],
197
+ ) -> None:
198
+
199
+ if id(value) in refers:
200
+ return output.append(
201
+ f'{prefix} {repeat}')
202
+
203
+ refers.add(id(value))
204
+
205
+
206
+ types = {
207
+ 'dict': dict,
208
+ 'list': list,
209
+ 'tuple': tuple,
210
+ 'set': set}
211
+
212
+ for name, _type in types.items():
213
+
214
+ if not isinstance(value, _type):
215
+ continue
216
+
217
+ output.append(
218
+ f'{prefix} '
219
+ f'<c{colors.label}>{name}<c0>')
220
+
221
+ return _process(
222
+ source=value,
223
+ indent=indent + 2,
224
+ refers=refers)
225
+
226
+
227
+ value = _concrete(value)
228
+
229
+ output.append(
230
+ f'{prefix} {value}')
231
+
232
+
233
+ def _concrete(
234
+ source: Any, # noqa: ANN401
235
+ ) -> str:
236
+
237
+ color = colors.other
238
+
239
+ if isinstance(source, bool):
240
+ color = colors.bool
241
+
242
+ if isinstance(source, int | float):
243
+ color = colors.num
244
+
245
+ elif isinstance(source, str):
246
+ color = colors.str
247
+
248
+ elif source is None:
249
+ color = colors.none
250
+
251
+ elif isinstance(source, Duration):
252
+ color = colors.times
253
+
254
+ elif isinstance(source, Times):
255
+ color = colors.times
256
+
257
+ elif source is Empty:
258
+ color = colors.empty
259
+
260
+ string = f'<c{color}>{source}<c0>'
261
+
262
+ if isinstance(source, str):
263
+ string = f"'{string}'"
264
+
265
+ return string
266
+
267
+
268
+ def _dict(
269
+ source: ANSIARRAD,
270
+ indent: int,
271
+ refers: Optional[set[int]] = None,
272
+ ) -> None:
273
+
274
+ assert isinstance(source, dict)
275
+
276
+ for key, value in source.items():
277
+
278
+ prefix = (
279
+ f'{" " * indent}'
280
+ f'<c{colors.key}>{key}'
281
+ f'<c{colors.colon}>:<c0>')
282
+
283
+ _append(
284
+ prefix, value, indent,
285
+ refers=refers or set())
286
+
287
+
288
+ def _list(
289
+ source: ANSIARRAL,
290
+ indent: int,
291
+ refers: Optional[set[int]] = None,
292
+ ) -> None:
293
+
294
+ assert isinstance(
295
+ source, (list, tuple, set))
296
+
297
+ for value in source:
298
+
299
+ prefix = (
300
+ f'{" " * indent}'
301
+ f'<c{colors.hyphen}>-<c0>')
302
+
303
+ _append(
304
+ prefix, value, indent,
305
+ refers=refers or set())
306
+
307
+
308
+ def _process(
309
+ source: ANSIARRAD | ANSIARRAL,
310
+ **kwargs: Any,
311
+ ) -> None:
312
+
313
+ if isinstance(source, dict):
314
+ return _dict(source, **kwargs)
315
+
316
+ return _list(source, **kwargs)
317
+
318
+
319
+ if isinstance(source, dict):
320
+ _dict(source, indent)
321
+
322
+ elif isinstance(source, list):
323
+ _list(source, indent)
324
+
325
+ elif isinstance(source, tuple):
326
+ _list(source, indent)
327
+
328
+ elif isinstance(source, set):
329
+ _list(source, indent)
330
+
331
+
332
+ _output = [
333
+ make_ansi(x) for x in output]
334
+
335
+ return '\n'.join(_output)
@@ -9,10 +9,15 @@ is permitted, for more information consult the project license file.
9
9
 
10
10
  from _pytest.capture import CaptureFixture
11
11
 
12
+ from ..stdout import array_ansi
12
13
  from ..stdout import kvpair_ansi
13
14
  from ..stdout import make_ansi
14
15
  from ..stdout import print_ansi
15
16
  from ..stdout import strip_ansi
17
+ from ...times import Duration
18
+ from ...times import Times
19
+ from ...times.common import UNIXMPOCH
20
+ from ...types import Empty
16
21
 
17
22
 
18
23
 
@@ -78,3 +83,149 @@ def test_strip_ansi() -> None:
78
83
  output = '\x1b[0;31mtest\x1b[0;0m'
79
84
 
80
85
  assert strip_ansi(output) == 'test'
86
+
87
+
88
+
89
+ def test_array_ansi() -> None: # noqa: CFQ001
90
+ """
91
+ Perform various tests associated with relevant routines.
92
+ """
93
+
94
+ simple = {
95
+ 'str': 'value',
96
+ 'list': [1, 2],
97
+ 'bool': False}
98
+
99
+ repeat = {
100
+ 'dict': simple | {
101
+ 'dict': simple}}
102
+
103
+ source = {
104
+ 'str': 'value',
105
+ 'int': 1,
106
+ 'float': 1.0,
107
+ 'complex': complex(3, 1),
108
+ 'list': [simple],
109
+ 'tuple': (simple,),
110
+ 'range': range(1, 3),
111
+ 'dict1': simple,
112
+ 'dict2': simple,
113
+ 'dict3': simple,
114
+ 'set': {1, 2, 3},
115
+ 'frozenset': {1, 2, 3},
116
+ 'bool': True,
117
+ 'none': None,
118
+ '_private': None,
119
+ 'repeat': repeat,
120
+ 'Empty': Empty,
121
+ 'Duration': Duration(190802),
122
+ 'Times': Times(0)}
123
+
124
+
125
+ output = strip_ansi(
126
+ array_ansi(simple))
127
+
128
+ assert output == (
129
+ "str: 'value'\n"
130
+ 'list: list\n'
131
+ ' - 1\n'
132
+ ' - 2\n'
133
+ 'bool: False')
134
+
135
+
136
+ output = strip_ansi(
137
+ array_ansi([simple]))
138
+
139
+ assert output == (
140
+ '- dict\n'
141
+ " str: 'value'\n"
142
+ ' list: list\n'
143
+ ' - 1\n'
144
+ ' - 2\n'
145
+ ' bool: False')
146
+
147
+
148
+ output = strip_ansi(
149
+ array_ansi((1, 2, 3)))
150
+
151
+ assert output == (
152
+ '- 1\n'
153
+ '- 2\n'
154
+ '- 3')
155
+
156
+
157
+ output = strip_ansi(
158
+ array_ansi({1, 2, 3}))
159
+
160
+ assert output == (
161
+ '- 1\n'
162
+ '- 2\n'
163
+ '- 3')
164
+
165
+
166
+ output = strip_ansi(
167
+ array_ansi(source))
168
+
169
+ assert output == (
170
+ "str: 'value'\n"
171
+ 'int: 1\n'
172
+ 'float: 1.0\n'
173
+ 'complex: (3+1j)\n'
174
+ 'list: list\n'
175
+ ' - dict\n'
176
+ " str: 'value'\n"
177
+ ' list: list\n'
178
+ ' - 1\n'
179
+ ' - 2\n'
180
+ ' bool: False\n'
181
+ 'tuple: tuple\n'
182
+ ' - dict\n'
183
+ " str: 'value'\n"
184
+ ' list: list\n'
185
+ ' - 1\n'
186
+ ' - 2\n'
187
+ ' bool: False\n'
188
+ 'range: range(1, 3)\n'
189
+ 'dict1: dict\n'
190
+ " str: 'value'\n"
191
+ ' list: list\n'
192
+ ' - 1\n'
193
+ ' - 2\n'
194
+ ' bool: False\n'
195
+ 'dict2: dict\n'
196
+ " str: 'value'\n"
197
+ ' list: list\n'
198
+ ' - 1\n'
199
+ ' - 2\n'
200
+ ' bool: False\n'
201
+ 'dict3: dict\n'
202
+ " str: 'value'\n"
203
+ ' list: list\n'
204
+ ' - 1\n'
205
+ ' - 2\n'
206
+ ' bool: False\n'
207
+ 'set: set\n'
208
+ ' - 1\n'
209
+ ' - 2\n'
210
+ ' - 3\n'
211
+ 'frozenset: set\n'
212
+ ' - 1\n'
213
+ ' - 2\n'
214
+ ' - 3\n'
215
+ 'bool: True\n'
216
+ 'none: None\n'
217
+ '_private: None\n'
218
+ 'repeat: dict\n'
219
+ ' dict: dict\n'
220
+ " str: 'value'\n"
221
+ ' list: list\n'
222
+ ' - 1\n'
223
+ ' - 2\n'
224
+ ' bool: False\n'
225
+ ' dict: dict\n'
226
+ ' str: REPEAT\n'
227
+ ' list: REPEAT\n'
228
+ ' bool: REPEAT\n'
229
+ 'Empty: Empty\n'
230
+ 'Duration: 2d5h\n'
231
+ f'Times: {UNIXMPOCH}')
encommon/version.txt CHANGED
@@ -1 +1 @@
1
- 0.6.0
1
+ 0.7.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: encommon
3
- Version: 0.6.0
3
+ Version: 0.7.0
4
4
  Summary: Enasis Network Common Library
5
5
  License: MIT
6
6
  Classifier: Programming Language :: Python :: 3
@@ -1,7 +1,7 @@
1
1
  encommon/__init__.py,sha256=VoXUcphq-gcXCraaU47EtXBftF6UVuQPMGr0fuCTt9A,525
2
2
  encommon/conftest.py,sha256=z5BMi6KjNuactDRgbh8J8w81V08Ptf6QK2o_bJANRs4,880
3
3
  encommon/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
- encommon/version.txt,sha256=l6XW5UCmEg0Jw53bZn4Ojiusf8wv_vgTuC4I_WA2W84,6
4
+ encommon/version.txt,sha256=ln2a-xATRmZxZvLnboGRC8GQSI19QdUMoAcunZLwDjI,6
5
5
  encommon/config/__init__.py,sha256=2ic7tK2lOQvqWmmQnMozqxCJcbyQ_sSEHmOUDUFan2U,710
6
6
  encommon/config/common.py,sha256=gaKBgkF7b7UIAhd0ESio0KpG8JfdRpz5BxNgKRptd6A,2041
7
7
  encommon/config/config.py,sha256=-wIkyA6YQGAly0WuXLaOYXENjZYRYgWk_VdUN8mMe8Q,4853
@@ -44,19 +44,19 @@ encommon/types/test/__init__.py,sha256=PjrnBYT0efyvbaGeNx94dm3tP3EVHUHSVs-VGeLEv
44
44
  encommon/types/test/test_dicts.py,sha256=UHMvrWKnz-bPscq0Vp2uoLLFv4slvQQL2sobe5WUZ7U,2673
45
45
  encommon/types/test/test_empty.py,sha256=YUn0ROFhrWLQ30uROVqroHW4BsnFbzUZjACs3aEvrrI,981
46
46
  encommon/types/test/test_strings.py,sha256=WHXf1dnK6Qs2_0UyGYztJxpS29bnR8WKjKsvVO2WCi4,407
47
- encommon/utils/__init__.py,sha256=qdr2RDKlmoGrgMhwJCaTrhQXmuD_lmDxlIxOUprnRVs,784
47
+ encommon/utils/__init__.py,sha256=bBiDsBz8j-fHJ-P-AM4rZKqfiLNv5Q8KID8GfcvpWLA,833
48
48
  encommon/utils/common.py,sha256=UrowELh3PtDzpSS48nGhsAxTS_QUk96-KEJa4MlxiMA,466
49
49
  encommon/utils/match.py,sha256=4L2d2Cvr7vp3odkRCdNQ10OIW8DkEP55_NbQ6bdsReo,2462
50
50
  encommon/utils/paths.py,sha256=4EeaPsVwpv3pzoHeWmiSSGYZEud6hkD27kvbvgSpOPs,3236
51
51
  encommon/utils/sample.py,sha256=hOhS6A2aB9a5kXfrst7gUSQkxuqEo2J1AFyBsJZQhHE,3169
52
- encommon/utils/stdout.py,sha256=0C5NTg8fAB25s5oKmsmV2VSERn22QFCZjqJ1S75SXOM,2779
52
+ encommon/utils/stdout.py,sha256=pPL68iE2oGk-hE3KGZjWE1vnOF6hflaarYPVZQnefHQ,7142
53
53
  encommon/utils/test/__init__.py,sha256=PjrnBYT0efyvbaGeNx94dm3tP3EVHUHSVs-VGeLEv5g,218
54
54
  encommon/utils/test/test_match.py,sha256=QagKpTFdRo23-Y55fSaJrSMpt5jIebScKbz0h8tivrI,1124
55
55
  encommon/utils/test/test_paths.py,sha256=0ls9gWJ2B487Dr1fHDDFCZPA7gxtv56nFEYHrTkNX-U,1892
56
56
  encommon/utils/test/test_sample.py,sha256=iNV9IxXmA5KJat3jKRiZH3iutHrT6bsibwti60AhICk,1464
57
- encommon/utils/test/test_stdout.py,sha256=a060uA8oEHFGoVqdwB5iYxdl4R2TRSgr6Z7pMEbxibs,1675
58
- encommon-0.6.0.dist-info/LICENSE,sha256=otnXKCtMjPlbHs0wgZ_BWULrp3g_2dWQJ6icRk9nkgg,1071
59
- encommon-0.6.0.dist-info/METADATA,sha256=OJ2Y0-tAC9HmFKQmrcyR5oQHFAVU1rxD9Rt2ssceXAs,2671
60
- encommon-0.6.0.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
61
- encommon-0.6.0.dist-info/top_level.txt,sha256=bP8q7-5tLDNm-3XPlqn_bDENfYNug5801H_xfz3BEAM,9
62
- encommon-0.6.0.dist-info/RECORD,,
57
+ encommon/utils/test/test_stdout.py,sha256=U3YD8XIfVjjh_vNxN1UJqOWyp7_OFtJVl2K5oMziPu8,4878
58
+ encommon-0.7.0.dist-info/LICENSE,sha256=otnXKCtMjPlbHs0wgZ_BWULrp3g_2dWQJ6icRk9nkgg,1071
59
+ encommon-0.7.0.dist-info/METADATA,sha256=as7cVGwmjhknmAnTKkAOi6hrVIXU07tWU0t83L4Fn_4,2671
60
+ encommon-0.7.0.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
61
+ encommon-0.7.0.dist-info/top_level.txt,sha256=bP8q7-5tLDNm-3XPlqn_bDENfYNug5801H_xfz3BEAM,9
62
+ encommon-0.7.0.dist-info/RECORD,,