encommon 0.6.0__tar.gz → 0.7.1__tar.gz

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.
Files changed (72) hide show
  1. {encommon-0.6.0/encommon.egg-info → encommon-0.7.1}/PKG-INFO +1 -1
  2. {encommon-0.6.0 → encommon-0.7.1}/encommon/config/logger.py +10 -1
  3. {encommon-0.6.0 → encommon-0.7.1}/encommon/config/test/test_logger.py +11 -7
  4. {encommon-0.6.0 → encommon-0.7.1}/encommon/utils/__init__.py +2 -0
  5. encommon-0.7.1/encommon/utils/stdout.py +338 -0
  6. encommon-0.7.1/encommon/utils/test/test_stdout.py +231 -0
  7. encommon-0.7.1/encommon/version.txt +1 -0
  8. {encommon-0.6.0 → encommon-0.7.1/encommon.egg-info}/PKG-INFO +1 -1
  9. {encommon-0.6.0 → encommon-0.7.1}/setup.cfg +2 -0
  10. encommon-0.6.0/encommon/utils/stdout.py +0 -123
  11. encommon-0.6.0/encommon/utils/test/test_stdout.py +0 -80
  12. encommon-0.6.0/encommon/version.txt +0 -1
  13. {encommon-0.6.0 → encommon-0.7.1}/LICENSE +0 -0
  14. {encommon-0.6.0 → encommon-0.7.1}/MANIFEST.in +0 -0
  15. {encommon-0.6.0 → encommon-0.7.1}/README.md +0 -0
  16. {encommon-0.6.0 → encommon-0.7.1}/encommon/__init__.py +0 -0
  17. {encommon-0.6.0 → encommon-0.7.1}/encommon/config/__init__.py +0 -0
  18. {encommon-0.6.0 → encommon-0.7.1}/encommon/config/common.py +0 -0
  19. {encommon-0.6.0 → encommon-0.7.1}/encommon/config/config.py +0 -0
  20. {encommon-0.6.0 → encommon-0.7.1}/encommon/config/files.py +0 -0
  21. {encommon-0.6.0 → encommon-0.7.1}/encommon/config/params.py +0 -0
  22. {encommon-0.6.0 → encommon-0.7.1}/encommon/config/paths.py +0 -0
  23. {encommon-0.6.0 → encommon-0.7.1}/encommon/config/test/__init__.py +0 -0
  24. {encommon-0.6.0 → encommon-0.7.1}/encommon/config/test/test_common.py +0 -0
  25. {encommon-0.6.0 → encommon-0.7.1}/encommon/config/test/test_config.py +0 -0
  26. {encommon-0.6.0 → encommon-0.7.1}/encommon/config/test/test_files.py +0 -0
  27. {encommon-0.6.0 → encommon-0.7.1}/encommon/config/test/test_paths.py +0 -0
  28. {encommon-0.6.0 → encommon-0.7.1}/encommon/conftest.py +0 -0
  29. {encommon-0.6.0 → encommon-0.7.1}/encommon/crypts/__init__.py +0 -0
  30. {encommon-0.6.0 → encommon-0.7.1}/encommon/crypts/crypts.py +0 -0
  31. {encommon-0.6.0 → encommon-0.7.1}/encommon/crypts/hashes.py +0 -0
  32. {encommon-0.6.0 → encommon-0.7.1}/encommon/crypts/params.py +0 -0
  33. {encommon-0.6.0 → encommon-0.7.1}/encommon/crypts/test/__init__.py +0 -0
  34. {encommon-0.6.0 → encommon-0.7.1}/encommon/crypts/test/test_crypts.py +0 -0
  35. {encommon-0.6.0 → encommon-0.7.1}/encommon/crypts/test/test_hashes.py +0 -0
  36. {encommon-0.6.0 → encommon-0.7.1}/encommon/py.typed +0 -0
  37. {encommon-0.6.0 → encommon-0.7.1}/encommon/times/__init__.py +0 -0
  38. {encommon-0.6.0 → encommon-0.7.1}/encommon/times/common.py +0 -0
  39. {encommon-0.6.0 → encommon-0.7.1}/encommon/times/duration.py +0 -0
  40. {encommon-0.6.0 → encommon-0.7.1}/encommon/times/parse.py +0 -0
  41. {encommon-0.6.0 → encommon-0.7.1}/encommon/times/test/__init__.py +0 -0
  42. {encommon-0.6.0 → encommon-0.7.1}/encommon/times/test/test_common.py +0 -0
  43. {encommon-0.6.0 → encommon-0.7.1}/encommon/times/test/test_duration.py +0 -0
  44. {encommon-0.6.0 → encommon-0.7.1}/encommon/times/test/test_parse.py +0 -0
  45. {encommon-0.6.0 → encommon-0.7.1}/encommon/times/test/test_timers.py +0 -0
  46. {encommon-0.6.0 → encommon-0.7.1}/encommon/times/test/test_times.py +0 -0
  47. {encommon-0.6.0 → encommon-0.7.1}/encommon/times/test/test_window.py +0 -0
  48. {encommon-0.6.0 → encommon-0.7.1}/encommon/times/timers.py +0 -0
  49. {encommon-0.6.0 → encommon-0.7.1}/encommon/times/times.py +0 -0
  50. {encommon-0.6.0 → encommon-0.7.1}/encommon/times/window.py +0 -0
  51. {encommon-0.6.0 → encommon-0.7.1}/encommon/types/__init__.py +0 -0
  52. {encommon-0.6.0 → encommon-0.7.1}/encommon/types/dicts.py +0 -0
  53. {encommon-0.6.0 → encommon-0.7.1}/encommon/types/empty.py +0 -0
  54. {encommon-0.6.0 → encommon-0.7.1}/encommon/types/strings.py +0 -0
  55. {encommon-0.6.0 → encommon-0.7.1}/encommon/types/test/__init__.py +0 -0
  56. {encommon-0.6.0 → encommon-0.7.1}/encommon/types/test/test_dicts.py +0 -0
  57. {encommon-0.6.0 → encommon-0.7.1}/encommon/types/test/test_empty.py +0 -0
  58. {encommon-0.6.0 → encommon-0.7.1}/encommon/types/test/test_strings.py +0 -0
  59. {encommon-0.6.0 → encommon-0.7.1}/encommon/utils/common.py +0 -0
  60. {encommon-0.6.0 → encommon-0.7.1}/encommon/utils/match.py +0 -0
  61. {encommon-0.6.0 → encommon-0.7.1}/encommon/utils/paths.py +0 -0
  62. {encommon-0.6.0 → encommon-0.7.1}/encommon/utils/sample.py +0 -0
  63. {encommon-0.6.0 → encommon-0.7.1}/encommon/utils/test/__init__.py +0 -0
  64. {encommon-0.6.0 → encommon-0.7.1}/encommon/utils/test/test_match.py +0 -0
  65. {encommon-0.6.0 → encommon-0.7.1}/encommon/utils/test/test_paths.py +0 -0
  66. {encommon-0.6.0 → encommon-0.7.1}/encommon/utils/test/test_sample.py +0 -0
  67. {encommon-0.6.0 → encommon-0.7.1}/encommon.egg-info/SOURCES.txt +0 -0
  68. {encommon-0.6.0 → encommon-0.7.1}/encommon.egg-info/dependency_links.txt +0 -0
  69. {encommon-0.6.0 → encommon-0.7.1}/encommon.egg-info/requires.txt +0 -0
  70. {encommon-0.6.0 → encommon-0.7.1}/encommon.egg-info/top_level.txt +0 -0
  71. {encommon-0.6.0 → encommon-0.7.1}/pyproject.toml +0 -0
  72. {encommon-0.6.0 → encommon-0.7.1}/reqs-install.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: encommon
3
- Version: 0.6.0
3
+ Version: 0.7.1
4
4
  Summary: Enasis Network Common Library
5
5
  License: MIT
6
6
  Classifier: Programming Language :: Python :: 3
@@ -60,7 +60,7 @@ class Message:
60
60
  -------
61
61
  >>> message = Message('info', '1970-01-01', foo='bar')
62
62
  >>> strip_ansi(message.stdo_output)
63
- 'level="info" time="1970-01-01T00:00:00+0000" foo="bar"'
63
+ 'level="info" time="1970-01-01T00:00:00Z" foo="bar"'
64
64
 
65
65
  :param level: Severity which log message is classified.
66
66
  :param time: What time the log message actually occurred.
@@ -95,6 +95,10 @@ class Message:
95
95
  if value in [None, Empty]:
96
96
  continue
97
97
 
98
+ if (key == 'elapsed'
99
+ and isinstance(value, float)):
100
+ value = round(value, 2)
101
+
98
102
  value = str(value)
99
103
 
100
104
  self.__fields[key] = value
@@ -190,6 +194,11 @@ class Message:
190
194
  fields |= dict(self.__fields)
191
195
 
192
196
 
197
+ fields['time'] = (
198
+ fields['time']
199
+ .replace('+0000', 'Z'))
200
+
201
+
193
202
  output: list[str] = []
194
203
 
195
204
  for key, value in fields.items():
@@ -14,7 +14,6 @@ from _pytest.logging import LogCaptureFixture
14
14
 
15
15
  from ..logger import Logger
16
16
  from ..logger import Message
17
- from ...times.common import UNIXEPOCH
18
17
  from ...times.common import UNIXMPOCH
19
18
  from ...utils.stdout import strip_ansi
20
19
 
@@ -35,7 +34,8 @@ def test_Message() -> None:
35
34
  int=1,
36
35
  list=[1, '2', 3],
37
36
  none=None,
38
- string='foo')
37
+ string='foo',
38
+ elapsed=0.69420)
39
39
 
40
40
  attrs = list(message.__dict__)
41
41
 
@@ -60,7 +60,8 @@ def test_Message() -> None:
60
60
  'float="1.0", '
61
61
  'int="1", '
62
62
  'list="[1, \'2\', 3]", '
63
- 'string="foo")')
63
+ 'string="foo", '
64
+ 'elapsed="0.69")')
64
65
 
65
66
  assert str(message) == repr(message)
66
67
 
@@ -73,19 +74,21 @@ def test_Message() -> None:
73
74
  'float': '1.0',
74
75
  'int': '1',
75
76
  'list': "[1, '2', 3]",
76
- 'string': 'foo'}
77
+ 'string': 'foo',
78
+ 'elapsed': '0.69'}
77
79
 
78
80
 
79
81
  output = strip_ansi(message.stdo_output)
80
82
 
81
83
  assert output == (
82
84
  'level="info"'
83
- f' time="{UNIXEPOCH}"'
85
+ ' time="1970-01-01T00:00:00Z"'
84
86
  ' dict="{\'foo\': \'bar\'}"'
85
87
  ' float="1.0"'
86
88
  ' int="1"'
87
89
  ' list="[1, \'2\', 3]"'
88
- ' string="foo"')
90
+ ' string="foo"'
91
+ ' elapsed="0.69"')
89
92
 
90
93
 
91
94
  assert message.file_output == (
@@ -95,7 +98,8 @@ def test_Message() -> None:
95
98
  ' "float": "1.0",'
96
99
  ' "int": "1",'
97
100
  ' "list": "[1, \'2\', 3]",'
98
- ' "string": "foo"}')
101
+ ' "string": "foo",'
102
+ ' "elapsed": "0.69"}')
99
103
 
100
104
 
101
105
 
@@ -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',
@@ -0,0 +1,338 @@
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 dataclasses import dataclass
11
+ from re import compile
12
+ from re import sub as re_sub
13
+ from sys import stdout
14
+ from typing import Any
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
22
+
23
+ from .common import JOINABLE
24
+
25
+
26
+
27
+ ANSICODE = compile(
28
+ r'\x1b\[[^A-Za-z]*[A-Za-z]')
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
+
64
+
65
+
66
+ def print_ansi(
67
+ string: str = '',
68
+ method: Literal['stdout', 'print'] = 'stdout',
69
+ output: bool = True,
70
+ ) -> str:
71
+ """
72
+ Print the ANSI colorized string to the standard output.
73
+
74
+ Example
75
+ -------
76
+ >>> print_ansi('<c91>ERROR<c0>')
77
+ '\\x1b[0;91mERROR\\x1b[0;0m'
78
+
79
+ :param string: String processed using inline directives.
80
+ :param method: Which method for standard output is used.
81
+ :param output: Whether or not hte output should be print.
82
+ :returns: ANSI colorized string using inline directives.
83
+ """ # noqa: D301 LIT102
84
+
85
+ string = make_ansi(string)
86
+
87
+ if output is True:
88
+ if method == 'stdout':
89
+ stdout.write(f'{string}\n')
90
+ else:
91
+ print(string) # noqa: T201
92
+
93
+ return string
94
+
95
+
96
+
97
+ def make_ansi(
98
+ string: str,
99
+ ) -> str:
100
+ """
101
+ Parse the string and replace directives with ANSI codes.
102
+
103
+ Example
104
+ -------
105
+ >>> make_ansi('<c91>ERROR<c0>')
106
+ '\\x1b[0;91mERROR\\x1b[0;0m'
107
+
108
+ :param string: String containing directives to replace.
109
+ :returns: Provided string with the directives replaced.
110
+ """ # noqa: D301 LIT102
111
+
112
+ pattern = r'\<c([\d\;]+)\>'
113
+ replace = r'\033[0;\1m'
114
+
115
+ return re_sub(pattern, replace, string)
116
+
117
+
118
+
119
+ def kvpair_ansi(
120
+ key: str,
121
+ value: Any, # noqa: ANN401
122
+ ) -> str:
123
+ """
124
+ Process and colorize keys and values for standard output.
125
+
126
+ Example
127
+ -------
128
+ >>> kvpair_ansi('k', 'v')
129
+ '\\x1b[0;90mk\\x1b[0;37m="\\x1b[0;0m...
130
+
131
+ :param key: String value to use for the key name portion.
132
+ :param value: String value to use for the value portion.
133
+ :returns: ANSI colorized string using inline directives.
134
+ """ # noqa: D301 LIT102
135
+
136
+ if isinstance(value, JOINABLE): # type: ignore
137
+ value = ','.join([
138
+ str(x) for x in value])
139
+
140
+ elif not isinstance(value, str):
141
+ value = str(value)
142
+
143
+ return make_ansi(
144
+ f'<c90>{key}<c37>="<c0>'
145
+ f'{value}<c37>"<c0>')
146
+
147
+
148
+
149
+ def strip_ansi(
150
+ string: str,
151
+ ) -> str:
152
+ """
153
+ Return the provided string with the ANSI codes removed.
154
+
155
+ Example
156
+ -------
157
+ >>> strip_ansi('\\x1b[0;91mERROR\\x1b[0;0m')
158
+ 'ERROR'
159
+
160
+ :param string: String which contains ANSI codes to strip.
161
+ :returns: Provided string with the ANSI codes removed.
162
+ """ # noqa: D301 LIT102
163
+
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
+
204
+ if isinstance(value, list | tuple | dict):
205
+ refers.add(id(value))
206
+
207
+
208
+ types = {
209
+ 'list': list,
210
+ 'tuple': tuple,
211
+ 'dict': dict,
212
+ 'frozenset': frozenset,
213
+ 'set': set}
214
+
215
+ for name, _type in types.items():
216
+
217
+ if not isinstance(value, _type):
218
+ continue
219
+
220
+ output.append(
221
+ f'{prefix} '
222
+ f'<c{colors.label}>{name}<c0>')
223
+
224
+ return _process(
225
+ source=value,
226
+ indent=indent + 2,
227
+ refers=refers)
228
+
229
+
230
+ value = _concrete(value)
231
+
232
+ output.append(
233
+ f'{prefix} {value}')
234
+
235
+
236
+ def _concrete(
237
+ source: Any, # noqa: ANN401
238
+ ) -> str:
239
+
240
+ color = colors.other
241
+
242
+ if isinstance(source, bool):
243
+ color = colors.bool
244
+
245
+ if isinstance(source, int | float):
246
+ color = colors.num
247
+
248
+ elif isinstance(source, str):
249
+ color = colors.str
250
+
251
+ elif source is None:
252
+ color = colors.none
253
+
254
+ elif isinstance(source, Duration):
255
+ color = colors.times
256
+
257
+ elif isinstance(source, Times):
258
+ color = colors.times
259
+
260
+ elif source is Empty:
261
+ color = colors.empty
262
+
263
+ string = f'<c{color}>{source}<c0>'
264
+
265
+ if isinstance(source, str):
266
+ string = f"'{string}'"
267
+
268
+ return string
269
+
270
+
271
+ def _dict(
272
+ source: ANSIARRAD,
273
+ indent: int,
274
+ refers: Optional[set[int]] = None,
275
+ ) -> None:
276
+
277
+ assert isinstance(source, dict)
278
+
279
+ for key, value in source.items():
280
+
281
+ prefix = (
282
+ f'{" " * indent}'
283
+ f'<c{colors.key}>{key}'
284
+ f'<c{colors.colon}>:<c0>')
285
+
286
+ _append(
287
+ prefix, value, indent,
288
+ refers=refers or set())
289
+
290
+
291
+ def _list(
292
+ source: ANSIARRAL,
293
+ indent: int,
294
+ refers: Optional[set[int]] = None,
295
+ ) -> None:
296
+
297
+ assert isinstance(
298
+ source, (list, tuple, set))
299
+
300
+ for value in source:
301
+
302
+ prefix = (
303
+ f'{" " * indent}'
304
+ f'<c{colors.hyphen}>-<c0>')
305
+
306
+ _append(
307
+ prefix, value, indent,
308
+ refers=refers or set())
309
+
310
+
311
+ def _process(
312
+ source: ANSIARRAD | ANSIARRAL,
313
+ **kwargs: Any,
314
+ ) -> None:
315
+
316
+ if isinstance(source, dict):
317
+ return _dict(source, **kwargs)
318
+
319
+ return _list(source, **kwargs)
320
+
321
+
322
+ if isinstance(source, dict):
323
+ _dict(source, indent)
324
+
325
+ elif isinstance(source, list):
326
+ _list(source, indent)
327
+
328
+ elif isinstance(source, tuple):
329
+ _list(source, indent)
330
+
331
+ elif isinstance(source, set):
332
+ _list(source, indent)
333
+
334
+
335
+ _output = [
336
+ make_ansi(x) for x in output]
337
+
338
+ return '\n'.join(_output)
@@ -0,0 +1,231 @@
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 _pytest.capture import CaptureFixture
11
+
12
+ from ..stdout import array_ansi
13
+ from ..stdout import kvpair_ansi
14
+ from ..stdout import make_ansi
15
+ from ..stdout import print_ansi
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
21
+
22
+
23
+
24
+ def test_print_ansi(
25
+ capsys: CaptureFixture[str],
26
+ ) -> None:
27
+ """
28
+ Perform various tests associated with relevant routines.
29
+
30
+ :param capsys: pytest object for capturing print message.
31
+ """
32
+
33
+ print_ansi('<c91>test<c0>', 'print')
34
+
35
+ output = capsys.readouterr().out
36
+
37
+ assert strip_ansi(output) == 'test\n'
38
+
39
+
40
+
41
+ def test_make_ansi() -> None:
42
+ """
43
+ Perform various tests associated with relevant routines.
44
+ """
45
+
46
+ output = make_ansi('<c31>test<c0>')
47
+
48
+ assert output == (
49
+ '\x1b[0;31mtest\x1b[0;0m')
50
+
51
+
52
+
53
+ def test_kvpair_ansi() -> None:
54
+ """
55
+ Perform various tests associated with relevant routines.
56
+ """
57
+
58
+ output = kvpair_ansi('key', 'value')
59
+
60
+ assert output == (
61
+ '\x1b[0;90mkey\x1b[0;37m="\x1b'
62
+ '[0;0mvalue\x1b[0;37m"\x1b[0;0m')
63
+
64
+ output = kvpair_ansi('key', [1, 2])
65
+
66
+ assert output == (
67
+ '\x1b[0;90mkey\x1b[0;37m="\x1b'
68
+ '[0;0m1,2\x1b[0;37m"\x1b[0;0m')
69
+
70
+ output = kvpair_ansi('key', None)
71
+
72
+ assert output == (
73
+ '\x1b[0;90mkey\x1b[0;37m="\x1b'
74
+ '[0;0mNone\x1b[0;37m"\x1b[0;0m')
75
+
76
+
77
+
78
+ def test_strip_ansi() -> None:
79
+ """
80
+ Perform various tests associated with relevant routines.
81
+ """
82
+
83
+ output = '\x1b[0;31mtest\x1b[0;0m'
84
+
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: 'value'\n"
227
+ ' list: REPEAT\n'
228
+ ' bool: False\n'
229
+ 'Empty: Empty\n'
230
+ 'Duration: 2d5h\n'
231
+ f'Times: {UNIXMPOCH}')
@@ -0,0 +1 @@
1
+ 0.7.1
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: encommon
3
- Version: 0.6.0
3
+ Version: 0.7.1
4
4
  Summary: Enasis Network Common Library
5
5
  License: MIT
6
6
  Classifier: Programming Language :: Python :: 3
@@ -12,6 +12,8 @@ ignore =
12
12
  per-file-ignores =
13
13
  encommon/crypts/hashes.py:S324,
14
14
  encommon/times/timers.py:S608,
15
+ encommon/utils/stdout.py:SIM114,
16
+ encommon/utils/test/test_stdout.py:LIT015,
15
17
 
16
18
  [mypy]
17
19
  mypy_path = stubs
@@ -1,123 +0,0 @@
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 re import compile
11
- from re import sub as re_sub
12
- from sys import stdout
13
- from typing import Any
14
- from typing import Literal
15
-
16
- from .common import JOINABLE
17
-
18
-
19
-
20
- ANSICODE = compile(
21
- r'\x1b\[[^A-Za-z]*[A-Za-z]')
22
-
23
-
24
-
25
- def print_ansi(
26
- string: str = '',
27
- method: Literal['stdout', 'print'] = 'stdout',
28
- output: bool = True,
29
- ) -> str:
30
- """
31
- Print the ANSI colorized string to the standard output.
32
-
33
- Example
34
- -------
35
- >>> print_ansi('<c91>ERROR<c0>')
36
- '\\x1b[0;91mERROR\\x1b[0;0m'
37
-
38
- :param string: String processed using inline directives.
39
- :param method: Which method for standard output is used.
40
- :param output: Whether or not hte output should be print.
41
- :returns: ANSI colorized string using inline directives.
42
- """ # noqa: D301 LIT102
43
-
44
- string = make_ansi(string)
45
-
46
- if output is True:
47
- if method == 'stdout':
48
- stdout.write(f'{string}\n')
49
- else:
50
- print(string) # noqa: T201
51
-
52
- return string
53
-
54
-
55
-
56
- def make_ansi(
57
- string: str,
58
- ) -> str:
59
- """
60
- Parse the string and replace directives with ANSI codes.
61
-
62
- Example
63
- -------
64
- >>> make_ansi('<c91>ERROR<c0>')
65
- '\\x1b[0;91mERROR\\x1b[0;0m'
66
-
67
- :param string: String containing directives to replace.
68
- :returns: Provided string with the directives replaced.
69
- """ # noqa: D301 LIT102
70
-
71
- pattern = r'\<c([\d\;]+)\>'
72
- replace = r'\033[0;\1m'
73
-
74
- return re_sub(pattern, replace, string)
75
-
76
-
77
-
78
- def kvpair_ansi(
79
- key: str,
80
- value: Any, # noqa: ANN401
81
- ) -> str:
82
- """
83
- Process and colorize keys and values for standard output.
84
-
85
- Example
86
- -------
87
- >>> kvpair_ansi('k', 'v')
88
- '\\x1b[0;90mk\\x1b[0;37m="\\x1b[0;0m...
89
-
90
- :param key: String value to use for the key name portion.
91
- :param value: String value to use for the value portion.
92
- :returns: ANSI colorized string using inline directives.
93
- """ # noqa: D301 LIT102
94
-
95
- if isinstance(value, JOINABLE): # type: ignore
96
- value = ','.join([
97
- str(x) for x in value])
98
-
99
- elif not isinstance(value, str):
100
- value = str(value)
101
-
102
- return make_ansi(
103
- f'<c90>{key}<c37>="<c0>'
104
- f'{value}<c37>"<c0>')
105
-
106
-
107
-
108
- def strip_ansi(
109
- string: str,
110
- ) -> str:
111
- """
112
- Return the provided string with the ANSI codes removed.
113
-
114
- Example
115
- -------
116
- >>> strip_ansi('\\x1b[0;91mERROR\\x1b[0;0m')
117
- 'ERROR'
118
-
119
- :param string: String which contains ANSI codes to strip.
120
- :returns: Provided string with the ANSI codes removed.
121
- """ # noqa: D301 LIT102
122
-
123
- return re_sub(ANSICODE, '', string)
@@ -1,80 +0,0 @@
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 _pytest.capture import CaptureFixture
11
-
12
- from ..stdout import kvpair_ansi
13
- from ..stdout import make_ansi
14
- from ..stdout import print_ansi
15
- from ..stdout import strip_ansi
16
-
17
-
18
-
19
- def test_print_ansi(
20
- capsys: CaptureFixture[str],
21
- ) -> None:
22
- """
23
- Perform various tests associated with relevant routines.
24
-
25
- :param capsys: pytest object for capturing print message.
26
- """
27
-
28
- print_ansi('<c91>test<c0>', 'print')
29
-
30
- output = capsys.readouterr().out
31
-
32
- assert strip_ansi(output) == 'test\n'
33
-
34
-
35
-
36
- def test_make_ansi() -> None:
37
- """
38
- Perform various tests associated with relevant routines.
39
- """
40
-
41
- output = make_ansi('<c31>test<c0>')
42
-
43
- assert output == (
44
- '\x1b[0;31mtest\x1b[0;0m')
45
-
46
-
47
-
48
- def test_kvpair_ansi() -> None:
49
- """
50
- Perform various tests associated with relevant routines.
51
- """
52
-
53
- output = kvpair_ansi('key', 'value')
54
-
55
- assert output == (
56
- '\x1b[0;90mkey\x1b[0;37m="\x1b'
57
- '[0;0mvalue\x1b[0;37m"\x1b[0;0m')
58
-
59
- output = kvpair_ansi('key', [1, 2])
60
-
61
- assert output == (
62
- '\x1b[0;90mkey\x1b[0;37m="\x1b'
63
- '[0;0m1,2\x1b[0;37m"\x1b[0;0m')
64
-
65
- output = kvpair_ansi('key', None)
66
-
67
- assert output == (
68
- '\x1b[0;90mkey\x1b[0;37m="\x1b'
69
- '[0;0mNone\x1b[0;37m"\x1b[0;0m')
70
-
71
-
72
-
73
- def test_strip_ansi() -> None:
74
- """
75
- Perform various tests associated with relevant routines.
76
- """
77
-
78
- output = '\x1b[0;31mtest\x1b[0;0m'
79
-
80
- assert strip_ansi(output) == 'test'
@@ -1 +0,0 @@
1
- 0.6.0
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes