encommon 0.9.0__py3-none-any.whl → 0.11.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/config/__init__.py +3 -3
- encommon/config/config.py +28 -2
- encommon/config/files.py +3 -3
- encommon/config/logger.py +37 -6
- encommon/config/params.py +24 -4
- encommon/config/paths.py +2 -2
- encommon/config/test/test_logger.py +3 -0
- encommon/config/test/{test_common.py → test_utils.py} +3 -3
- encommon/config/{common.py → utils.py} +1 -10
- encommon/conftest.py +4 -4
- encommon/crypts/crypts.py +23 -22
- encommon/crypts/params.py +15 -2
- encommon/crypts/test/test_crypts.py +8 -20
- encommon/times/__init__.py +14 -2
- encommon/times/common.py +0 -127
- encommon/times/params.py +155 -0
- encommon/times/parse.py +5 -5
- encommon/times/test/test_params.py +64 -0
- encommon/times/test/test_parse.py +1 -1
- encommon/times/test/test_timer.py +86 -0
- encommon/times/test/test_timers.py +87 -36
- encommon/times/test/{test_common.py → test_utils.py} +3 -3
- encommon/times/test/test_window.py +101 -51
- encommon/times/test/test_windows.py +264 -0
- encommon/times/timer.py +147 -0
- encommon/times/timers.py +207 -133
- encommon/times/times.py +6 -6
- encommon/times/utils.py +148 -0
- encommon/times/window.py +124 -85
- encommon/times/windows.py +459 -0
- encommon/types/__init__.py +6 -0
- encommon/types/notate.py +319 -0
- encommon/types/test/__init__.py +37 -0
- encommon/types/test/test_dicts.py +23 -28
- encommon/types/test/test_notate.py +217 -0
- encommon/utils/__init__.py +2 -2
- encommon/utils/common.py +0 -39
- encommon/utils/files.py +71 -0
- encommon/utils/paths.py +1 -1
- encommon/utils/sample.py +2 -2
- encommon/utils/test/{test_common.py → test_files.py} +2 -2
- encommon/utils/test/test_paths.py +2 -1
- encommon/version.txt +1 -1
- {encommon-0.9.0.dist-info → encommon-0.11.0.dist-info}/METADATA +1 -1
- encommon-0.11.0.dist-info/RECORD +73 -0
- encommon-0.9.0.dist-info/RECORD +0 -63
- {encommon-0.9.0.dist-info → encommon-0.11.0.dist-info}/LICENSE +0 -0
- {encommon-0.9.0.dist-info → encommon-0.11.0.dist-info}/WHEEL +0 -0
- {encommon-0.9.0.dist-info → encommon-0.11.0.dist-info}/top_level.txt +0 -0
encommon/types/notate.py
ADDED
@@ -0,0 +1,319 @@
|
|
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 contextlib import suppress
|
11
|
+
from re import compile
|
12
|
+
from re import match as re_match
|
13
|
+
from typing import Any
|
14
|
+
from typing import Optional
|
15
|
+
from typing import Union
|
16
|
+
|
17
|
+
from .empty import Empty
|
18
|
+
|
19
|
+
|
20
|
+
|
21
|
+
_INTEGER = compile(r'^\d+$')
|
22
|
+
_INDICES = (list, tuple, dict)
|
23
|
+
_RECURSE = dict
|
24
|
+
|
25
|
+
|
26
|
+
|
27
|
+
_SETABLE = Union[
|
28
|
+
dict[str, Any],
|
29
|
+
list[Any]]
|
30
|
+
|
31
|
+
_GETABLE = Union[
|
32
|
+
tuple[Any, ...],
|
33
|
+
_SETABLE]
|
34
|
+
|
35
|
+
|
36
|
+
|
37
|
+
def getate(
|
38
|
+
source: _GETABLE,
|
39
|
+
path: str,
|
40
|
+
default: Optional[Any] = None,
|
41
|
+
delim: str = '/',
|
42
|
+
) -> Any: # noqa: ANN401
|
43
|
+
"""
|
44
|
+
Collect the value within the dictionary using notation.
|
45
|
+
|
46
|
+
Example
|
47
|
+
-------
|
48
|
+
>>> source = {'foo': {'bar': 'baz'}}
|
49
|
+
>>> getate(source, 'foo/bar')
|
50
|
+
'baz'
|
51
|
+
|
52
|
+
Example
|
53
|
+
-------
|
54
|
+
>>> source = {'foo': ['bar', 'baz']}
|
55
|
+
>>> getate(source, 'foo/1')
|
56
|
+
'baz'
|
57
|
+
|
58
|
+
:param source: Dictionary object processed in notation.
|
59
|
+
:param path: Path to the value within the source object.
|
60
|
+
:param default: Value to use if none is found in source.
|
61
|
+
:param delim: Override default delimiter between parts.
|
62
|
+
:returns: Value that was located within provided source.
|
63
|
+
"""
|
64
|
+
|
65
|
+
sourze: Any = source
|
66
|
+
|
67
|
+
split = path.split(delim)
|
68
|
+
|
69
|
+
length = len(split)
|
70
|
+
|
71
|
+
|
72
|
+
items = enumerate(split)
|
73
|
+
|
74
|
+
for index, base in items:
|
75
|
+
|
76
|
+
if sourze is Empty:
|
77
|
+
return default
|
78
|
+
|
79
|
+
|
80
|
+
indices = isinstance(
|
81
|
+
sourze, _INDICES)
|
82
|
+
|
83
|
+
if (indices is False
|
84
|
+
and index < length):
|
85
|
+
return default
|
86
|
+
|
87
|
+
|
88
|
+
recurse = isinstance(
|
89
|
+
sourze, _RECURSE)
|
90
|
+
|
91
|
+
if recurse is False:
|
92
|
+
|
93
|
+
with suppress(IndexError):
|
94
|
+
sourze = sourze[int(base)]
|
95
|
+
continue
|
96
|
+
|
97
|
+
|
98
|
+
if base not in sourze:
|
99
|
+
sourze = Empty
|
100
|
+
continue
|
101
|
+
|
102
|
+
sourze = sourze[base]
|
103
|
+
|
104
|
+
|
105
|
+
return (
|
106
|
+
default if sourze is Empty
|
107
|
+
else sourze)
|
108
|
+
|
109
|
+
|
110
|
+
|
111
|
+
def setate(
|
112
|
+
source: _SETABLE,
|
113
|
+
path: str,
|
114
|
+
value: Any, # noqa: ANN401
|
115
|
+
delim: str = '/',
|
116
|
+
) -> None:
|
117
|
+
"""
|
118
|
+
Define the value within the dictionary using notation.
|
119
|
+
|
120
|
+
Example
|
121
|
+
-------
|
122
|
+
>>> source = {'foo': {'bar': 'baz'}}
|
123
|
+
>>> source['foo']['bar']
|
124
|
+
'baz'
|
125
|
+
>>> setate(source, 'foo/bar', 'bop')
|
126
|
+
>>> source['foo']['bar']
|
127
|
+
'bop'
|
128
|
+
|
129
|
+
:param source: Dictionary object processed in notation.
|
130
|
+
:param path: Path to the value within the source object.
|
131
|
+
:param value: Value which will be defined at noted point.
|
132
|
+
:param delim: Override default delimiter between parts.
|
133
|
+
"""
|
134
|
+
|
135
|
+
_setvalue(source, path, value, delim)
|
136
|
+
|
137
|
+
|
138
|
+
|
139
|
+
def delate(
|
140
|
+
source: _SETABLE,
|
141
|
+
path: str,
|
142
|
+
delim: str = '/',
|
143
|
+
) -> None:
|
144
|
+
"""
|
145
|
+
Delete the value within the dictionary using notation.
|
146
|
+
|
147
|
+
Example
|
148
|
+
-------
|
149
|
+
>>> source = {'foo': {'bar': 'baz'}}
|
150
|
+
>>> delate(source, 'foo/bar')
|
151
|
+
>>> source
|
152
|
+
{'foo': {}}
|
153
|
+
|
154
|
+
:param source: Dictionary object processed in notation.
|
155
|
+
:param path: Path to the value within the source object.
|
156
|
+
:param delim: Override default delimiter between parts.
|
157
|
+
"""
|
158
|
+
|
159
|
+
split = path.split(delim)
|
160
|
+
|
161
|
+
with suppress(KeyError, IndexError):
|
162
|
+
|
163
|
+
|
164
|
+
for part in split[:-1]:
|
165
|
+
|
166
|
+
setable = isinstance(
|
167
|
+
source, dict | list)
|
168
|
+
|
169
|
+
if setable is False:
|
170
|
+
raise ValueError('source')
|
171
|
+
|
172
|
+
if isinstance(source, list):
|
173
|
+
source = source[int(part)]
|
174
|
+
|
175
|
+
elif isinstance(source, dict):
|
176
|
+
source = source[part]
|
177
|
+
|
178
|
+
|
179
|
+
part = split[-1]
|
180
|
+
|
181
|
+
setable = isinstance(
|
182
|
+
source, dict | list)
|
183
|
+
|
184
|
+
if setable is False:
|
185
|
+
raise ValueError('source')
|
186
|
+
|
187
|
+
if isinstance(source, dict):
|
188
|
+
del source[part]
|
189
|
+
|
190
|
+
if isinstance(source, list):
|
191
|
+
del source[int(part)]
|
192
|
+
|
193
|
+
|
194
|
+
|
195
|
+
def _setpath(
|
196
|
+
source: _SETABLE,
|
197
|
+
path: str,
|
198
|
+
value: Any, # noqa: ANN401
|
199
|
+
delim: str = '/',
|
200
|
+
) -> None:
|
201
|
+
"""
|
202
|
+
Define the value within the dictionary using notation.
|
203
|
+
|
204
|
+
.. note::
|
205
|
+
This is a private helper function that could change.
|
206
|
+
|
207
|
+
:param source: Dictionary object processed in notation.
|
208
|
+
:param path: Path to the value within the source object.
|
209
|
+
:param value: Value which will be defined at noted point.
|
210
|
+
:param delim: Override default delimiter between parts.
|
211
|
+
"""
|
212
|
+
|
213
|
+
|
214
|
+
setable = isinstance(
|
215
|
+
source, dict | list)
|
216
|
+
|
217
|
+
assert setable is True
|
218
|
+
|
219
|
+
|
220
|
+
base, path = (
|
221
|
+
path.split(delim, 1))
|
222
|
+
|
223
|
+
next = (
|
224
|
+
path.split(delim, 1)[0])
|
225
|
+
|
226
|
+
|
227
|
+
default: _SETABLE = {}
|
228
|
+
|
229
|
+
if re_match(_INTEGER, next):
|
230
|
+
default = []
|
231
|
+
|
232
|
+
update: Any
|
233
|
+
|
234
|
+
|
235
|
+
if isinstance(source, list):
|
236
|
+
|
237
|
+
length = len(source)
|
238
|
+
index = int(base)
|
239
|
+
|
240
|
+
update = default
|
241
|
+
|
242
|
+
with suppress(IndexError):
|
243
|
+
update = source[index]
|
244
|
+
|
245
|
+
_setvalue(
|
246
|
+
update, path,
|
247
|
+
value, delim)
|
248
|
+
|
249
|
+
if length == index:
|
250
|
+
source.append(update)
|
251
|
+
|
252
|
+
elif length > index:
|
253
|
+
source[index] = update
|
254
|
+
|
255
|
+
|
256
|
+
elif isinstance(source, dict):
|
257
|
+
|
258
|
+
update = default
|
259
|
+
|
260
|
+
with suppress(KeyError):
|
261
|
+
update = source[base]
|
262
|
+
|
263
|
+
_setvalue(
|
264
|
+
update, path,
|
265
|
+
value, delim)
|
266
|
+
|
267
|
+
source[base] = update
|
268
|
+
|
269
|
+
|
270
|
+
|
271
|
+
def _setvalue(
|
272
|
+
source: _SETABLE,
|
273
|
+
path: str,
|
274
|
+
value: Any, # noqa: ANN401
|
275
|
+
delim: str = '/',
|
276
|
+
) -> None:
|
277
|
+
"""
|
278
|
+
Define the value within the dictionary using notation.
|
279
|
+
|
280
|
+
.. note::
|
281
|
+
This is a private helper function that could change.
|
282
|
+
|
283
|
+
:param source: Dictionary object processed in notation.
|
284
|
+
:param path: Path to the value within the source object.
|
285
|
+
:param value: Value which will be defined at noted point.
|
286
|
+
:param delim: Override default delimiter between parts.
|
287
|
+
"""
|
288
|
+
|
289
|
+
|
290
|
+
setable = isinstance(
|
291
|
+
source, dict | list)
|
292
|
+
|
293
|
+
if setable is False:
|
294
|
+
raise ValueError('source')
|
295
|
+
|
296
|
+
|
297
|
+
if delim in path:
|
298
|
+
return _setpath(
|
299
|
+
source, path,
|
300
|
+
value, delim)
|
301
|
+
|
302
|
+
|
303
|
+
if isinstance(source, list):
|
304
|
+
|
305
|
+
length = len(source)
|
306
|
+
index = int(path)
|
307
|
+
|
308
|
+
if index > length:
|
309
|
+
raise IndexError(index)
|
310
|
+
|
311
|
+
if length == index:
|
312
|
+
source.append(value)
|
313
|
+
|
314
|
+
elif length > index:
|
315
|
+
source[index] = value
|
316
|
+
|
317
|
+
|
318
|
+
if isinstance(source, dict):
|
319
|
+
source[path] = value
|
encommon/types/test/__init__.py
CHANGED
@@ -4,3 +4,40 @@ Functions and routines associated with Enasis Network Common Library.
|
|
4
4
|
This file is part of Enasis Network software eco-system. Distribution
|
5
5
|
is permitted, for more information consult the project license file.
|
6
6
|
"""
|
7
|
+
|
8
|
+
|
9
|
+
|
10
|
+
from copy import deepcopy
|
11
|
+
|
12
|
+
|
13
|
+
|
14
|
+
_DICT1 = {
|
15
|
+
'dict1': 'dict1',
|
16
|
+
'str': 'd1string',
|
17
|
+
'list': ['d1list'],
|
18
|
+
'tuple': (1, 2),
|
19
|
+
'dict': {'key': 'd1dict'},
|
20
|
+
'bool': False}
|
21
|
+
|
22
|
+
_DICT2 = {
|
23
|
+
'dict2': 'dict2',
|
24
|
+
'str': 'd2string',
|
25
|
+
'list': ['d2list'],
|
26
|
+
'tuple': (3, 4),
|
27
|
+
'dict': {'key': 'd2dict'},
|
28
|
+
'bool': True}
|
29
|
+
|
30
|
+
_DICT1R = deepcopy(_DICT1)
|
31
|
+
_DICT2R = deepcopy(_DICT2)
|
32
|
+
|
33
|
+
_DICT1R['recurse'] = (
|
34
|
+
deepcopy(_DICT1))
|
35
|
+
|
36
|
+
_DICT2R['recurse'] = (
|
37
|
+
deepcopy(_DICT2))
|
38
|
+
|
39
|
+
_DICT1R['nested'] = [
|
40
|
+
deepcopy(_DICT1)]
|
41
|
+
|
42
|
+
_DICT2R['nested'] = [
|
43
|
+
deepcopy(_DICT2)]
|
@@ -9,37 +9,22 @@ is permitted, for more information consult the project license file.
|
|
9
9
|
|
10
10
|
from copy import deepcopy
|
11
11
|
|
12
|
+
from . import _DICT1
|
13
|
+
from . import _DICT1R
|
14
|
+
from . import _DICT2
|
15
|
+
from . import _DICT2R
|
12
16
|
from ..dicts import merge_dicts
|
13
17
|
from ..dicts import sort_dict
|
14
18
|
|
15
19
|
|
16
20
|
|
17
|
-
_DICT1 = {
|
18
|
-
'dict1': 'dict1',
|
19
|
-
'str': 'd1string',
|
20
|
-
'list': ['d1list'],
|
21
|
-
'dict': {'key': 'd1value'},
|
22
|
-
'bool': False}
|
23
|
-
|
24
|
-
_DICT2 = {
|
25
|
-
'dict2': 'dict2',
|
26
|
-
'str': 'd2string',
|
27
|
-
'list': ['d2list'],
|
28
|
-
'dict': {'key': 'd2value'},
|
29
|
-
'bool': True}
|
30
|
-
|
31
|
-
|
32
|
-
|
33
21
|
def test_merge_dicts() -> None:
|
34
22
|
"""
|
35
23
|
Perform various tests associated with relevant routines.
|
36
24
|
"""
|
37
25
|
|
38
|
-
dict1 = deepcopy(
|
39
|
-
dict2 = deepcopy(
|
40
|
-
|
41
|
-
dict1['recurse'] = deepcopy(dict1)
|
42
|
-
dict2['recurse'] = deepcopy(dict2)
|
26
|
+
dict1 = deepcopy(_DICT1R)
|
27
|
+
dict2 = deepcopy(_DICT2R)
|
43
28
|
|
44
29
|
|
45
30
|
source = deepcopy(dict1)
|
@@ -52,14 +37,17 @@ def test_merge_dicts() -> None:
|
|
52
37
|
'dict2': 'dict2',
|
53
38
|
'str': 'd1string',
|
54
39
|
'list': ['d1list', 'd2list'],
|
55
|
-
'dict': {'key': '
|
40
|
+
'dict': {'key': 'd1dict'},
|
41
|
+
'tuple': (1, 2),
|
56
42
|
'bool': False,
|
43
|
+
'nested': [_DICT1, _DICT2],
|
57
44
|
'recurse': {
|
58
45
|
'dict1': 'dict1',
|
59
46
|
'dict2': 'dict2',
|
60
47
|
'str': 'd1string',
|
61
48
|
'list': ['d1list', 'd2list'],
|
62
|
-
'dict': {'key': '
|
49
|
+
'dict': {'key': 'd1dict'},
|
50
|
+
'tuple': (1, 2),
|
63
51
|
'bool': False}}
|
64
52
|
|
65
53
|
|
@@ -73,14 +61,17 @@ def test_merge_dicts() -> None:
|
|
73
61
|
'dict2': 'dict2',
|
74
62
|
'str': 'd2string',
|
75
63
|
'list': ['d1list', 'd2list'],
|
76
|
-
'dict': {'key': '
|
64
|
+
'dict': {'key': 'd2dict'},
|
65
|
+
'tuple': (3, 4),
|
77
66
|
'bool': True,
|
67
|
+
'nested': [_DICT1, _DICT2],
|
78
68
|
'recurse': {
|
79
69
|
'dict1': 'dict1',
|
80
70
|
'dict2': 'dict2',
|
81
71
|
'str': 'd2string',
|
82
72
|
'list': ['d1list', 'd2list'],
|
83
|
-
'dict': {'key': '
|
73
|
+
'dict': {'key': 'd2dict'},
|
74
|
+
'tuple': (3, 4),
|
84
75
|
'bool': True}}
|
85
76
|
|
86
77
|
|
@@ -98,13 +89,16 @@ def test_merge_dicts() -> None:
|
|
98
89
|
'dict2': 'dict2',
|
99
90
|
'str': 'd1string',
|
100
91
|
'list': ['d1list'],
|
101
|
-
'dict': {'key': '
|
92
|
+
'dict': {'key': 'd1dict'},
|
93
|
+
'tuple': (1, 2),
|
102
94
|
'bool': False,
|
95
|
+
'nested': [_DICT1],
|
103
96
|
'recurse': {
|
104
97
|
'dict1': 'dict1',
|
105
98
|
'str': 'd1string',
|
106
99
|
'list': ['d1list'],
|
107
|
-
'dict': {'key': '
|
100
|
+
'dict': {'key': 'd1dict'},
|
101
|
+
'tuple': (1, 2),
|
108
102
|
'bool': False}}
|
109
103
|
|
110
104
|
|
@@ -116,7 +110,8 @@ def test_sort_dict() -> None:
|
|
116
110
|
|
117
111
|
assert sort_dict(_DICT1) == {
|
118
112
|
'bool': False,
|
119
|
-
'dict': {'key': '
|
113
|
+
'dict': {'key': 'd1dict'},
|
114
|
+
'tuple': (1, 2),
|
120
115
|
'dict1': 'dict1',
|
121
116
|
'list': ['d1list'],
|
122
117
|
'str': 'd1string'}
|
@@ -0,0 +1,217 @@
|
|
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 copy import deepcopy
|
11
|
+
|
12
|
+
from _pytest.python_api import RaisesContext
|
13
|
+
|
14
|
+
from pytest import raises
|
15
|
+
|
16
|
+
from . import _DICT1R
|
17
|
+
from ..notate import delate
|
18
|
+
from ..notate import getate
|
19
|
+
from ..notate import setate
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
def test_getate() -> None:
|
24
|
+
"""
|
25
|
+
Perform various tests associated with relevant routines.
|
26
|
+
"""
|
27
|
+
|
28
|
+
source = deepcopy(_DICT1R)
|
29
|
+
|
30
|
+
|
31
|
+
value = getate(['1', 2], '1')
|
32
|
+
assert value == 2
|
33
|
+
|
34
|
+
value = getate((1, 2), '1')
|
35
|
+
assert value == 2
|
36
|
+
|
37
|
+
value = getate({'1': 2}, '1')
|
38
|
+
assert value == 2
|
39
|
+
|
40
|
+
|
41
|
+
path = 'recurse/dict/key'
|
42
|
+
value = getate(source, path)
|
43
|
+
|
44
|
+
assert value == 'd1dict'
|
45
|
+
|
46
|
+
|
47
|
+
path = 'recurse/list/0'
|
48
|
+
value = getate(source, path)
|
49
|
+
|
50
|
+
assert value == 'd1list'
|
51
|
+
|
52
|
+
|
53
|
+
|
54
|
+
def test_getate_cover() -> None:
|
55
|
+
"""
|
56
|
+
Perform various tests associated with relevant routines.
|
57
|
+
"""
|
58
|
+
|
59
|
+
source = deepcopy(_DICT1R)
|
60
|
+
|
61
|
+
|
62
|
+
assert not getate({}, 'd/n/e')
|
63
|
+
assert not getate([], '0/n/e')
|
64
|
+
|
65
|
+
|
66
|
+
path = 'recurse/str/a'
|
67
|
+
value = getate(source, path)
|
68
|
+
|
69
|
+
assert value is None
|
70
|
+
|
71
|
+
|
72
|
+
|
73
|
+
def test_setate() -> None:
|
74
|
+
"""
|
75
|
+
Perform various tests associated with relevant routines.
|
76
|
+
"""
|
77
|
+
|
78
|
+
source = deepcopy(_DICT1R)
|
79
|
+
|
80
|
+
|
81
|
+
path = 'list/1'
|
82
|
+
before = getate(source, path)
|
83
|
+
setate(source, path, 1)
|
84
|
+
after = getate(source, path)
|
85
|
+
assert after == 1
|
86
|
+
assert before is None
|
87
|
+
|
88
|
+
|
89
|
+
path = 'recurse/dict/key'
|
90
|
+
before = getate(source, path)
|
91
|
+
setate(source, path, 1)
|
92
|
+
after = getate(source, path)
|
93
|
+
assert after == 1
|
94
|
+
assert before == 'd1dict'
|
95
|
+
|
96
|
+
|
97
|
+
path = 'nested/0/dict/key'
|
98
|
+
before = getate(source, path)
|
99
|
+
setate(source, path, 1)
|
100
|
+
after = getate(source, path)
|
101
|
+
assert after == 1
|
102
|
+
assert before == 'd1dict'
|
103
|
+
|
104
|
+
|
105
|
+
path = 'recurse/list/0'
|
106
|
+
before = getate(source, path)
|
107
|
+
setate(source, path, 1)
|
108
|
+
after = getate(source, path)
|
109
|
+
assert after == 1
|
110
|
+
assert before == 'd1list'
|
111
|
+
|
112
|
+
|
113
|
+
|
114
|
+
def test_setate_cover() -> None:
|
115
|
+
"""
|
116
|
+
Perform various tests associated with relevant routines.
|
117
|
+
"""
|
118
|
+
|
119
|
+
source = deepcopy(_DICT1R)
|
120
|
+
|
121
|
+
|
122
|
+
path = 'nested/1/dict/key'
|
123
|
+
before = getate(source, path)
|
124
|
+
setate(source, path, 1)
|
125
|
+
after = getate(source, path)
|
126
|
+
assert after == 1
|
127
|
+
assert before is None
|
128
|
+
|
129
|
+
|
130
|
+
|
131
|
+
def test_setate_raises() -> None:
|
132
|
+
"""
|
133
|
+
Perform various tests associated with relevant routines.
|
134
|
+
"""
|
135
|
+
|
136
|
+
_raises: RaisesContext[
|
137
|
+
ValueError | IndexError]
|
138
|
+
|
139
|
+
|
140
|
+
_raises = raises(ValueError)
|
141
|
+
|
142
|
+
with _raises as reason:
|
143
|
+
setate(1, '1', 1) # type: ignore
|
144
|
+
|
145
|
+
_reason = str(reason.value)
|
146
|
+
|
147
|
+
assert _reason == 'source'
|
148
|
+
|
149
|
+
|
150
|
+
_raises = raises(IndexError)
|
151
|
+
|
152
|
+
with _raises as reason:
|
153
|
+
setate([], '1', 1)
|
154
|
+
|
155
|
+
_reason = str(reason.value)
|
156
|
+
|
157
|
+
assert _reason == '1'
|
158
|
+
|
159
|
+
|
160
|
+
|
161
|
+
def test_delate() -> None:
|
162
|
+
"""
|
163
|
+
Perform various tests associated with relevant routines.
|
164
|
+
"""
|
165
|
+
|
166
|
+
source = deepcopy(_DICT1R)
|
167
|
+
|
168
|
+
|
169
|
+
path = 'recurse/dict/key'
|
170
|
+
before = getate(source, path)
|
171
|
+
delate(source, path)
|
172
|
+
after = getate(source, path)
|
173
|
+
assert after is None
|
174
|
+
assert before == 'd1dict'
|
175
|
+
|
176
|
+
|
177
|
+
path = 'nested/0/dict/key'
|
178
|
+
before = getate(source, path)
|
179
|
+
delate(source, path)
|
180
|
+
after = getate(source, path)
|
181
|
+
assert after is None
|
182
|
+
assert before == 'd1dict'
|
183
|
+
|
184
|
+
|
185
|
+
path = 'recurse/list/0'
|
186
|
+
before = getate(source, path)
|
187
|
+
delate(source, path)
|
188
|
+
after = getate(source, path)
|
189
|
+
assert after is None
|
190
|
+
assert before == 'd1list'
|
191
|
+
|
192
|
+
|
193
|
+
|
194
|
+
def test_delate_raises() -> None:
|
195
|
+
"""
|
196
|
+
Perform various tests associated with relevant routines.
|
197
|
+
"""
|
198
|
+
|
199
|
+
|
200
|
+
_raises = raises(ValueError)
|
201
|
+
|
202
|
+
with _raises as reason:
|
203
|
+
delate(1, '1') # type: ignore
|
204
|
+
|
205
|
+
_reason = str(reason.value)
|
206
|
+
|
207
|
+
assert _reason == 'source'
|
208
|
+
|
209
|
+
|
210
|
+
_raises = raises(ValueError)
|
211
|
+
|
212
|
+
with _raises as reason:
|
213
|
+
delate({'a': 1}, 'a/1/c')
|
214
|
+
|
215
|
+
_reason = str(reason.value)
|
216
|
+
|
217
|
+
assert _reason == 'source'
|
encommon/utils/__init__.py
CHANGED
@@ -7,8 +7,8 @@ is permitted, for more information consult the project license file.
|
|
7
7
|
|
8
8
|
|
9
9
|
|
10
|
-
from .
|
11
|
-
from .
|
10
|
+
from .files import read_text
|
11
|
+
from .files import save_text
|
12
12
|
from .match import fuzz_match
|
13
13
|
from .match import rgxp_match
|
14
14
|
from .paths import resolve_path
|