encommon 0.20.4__tar.gz → 0.21.0__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. {encommon-0.20.4/encommon.egg-info → encommon-0.21.0}/PKG-INFO +3 -2
  2. {encommon-0.20.4 → encommon-0.21.0}/README.md +1 -0
  3. {encommon-0.20.4 → encommon-0.21.0}/encommon/colors/color.py +10 -5
  4. {encommon-0.20.4 → encommon-0.21.0}/encommon/colors/test/test_color.py +1 -1
  5. {encommon-0.20.4 → encommon-0.21.0}/encommon/types/__init__.py +4 -0
  6. {encommon-0.20.4 → encommon-0.21.0}/encommon/types/notate.py +179 -0
  7. {encommon-0.20.4 → encommon-0.21.0}/encommon/types/test/__init__.py +7 -0
  8. {encommon-0.20.4 → encommon-0.21.0}/encommon/types/test/test_dicts.py +1 -0
  9. encommon-0.21.0/encommon/types/test/test_notate.py +478 -0
  10. encommon-0.21.0/encommon/version.txt +1 -0
  11. {encommon-0.20.4 → encommon-0.21.0/encommon.egg-info}/PKG-INFO +3 -2
  12. encommon-0.20.4/encommon/types/test/test_notate.py +0 -217
  13. encommon-0.20.4/encommon/version.txt +0 -1
  14. {encommon-0.20.4 → encommon-0.21.0}/LICENSE +0 -0
  15. {encommon-0.20.4 → encommon-0.21.0}/MANIFEST.in +0 -0
  16. {encommon-0.20.4 → encommon-0.21.0}/encommon/__init__.py +0 -0
  17. {encommon-0.20.4 → encommon-0.21.0}/encommon/colors/__init__.py +0 -0
  18. {encommon-0.20.4 → encommon-0.21.0}/encommon/colors/test/__init__.py +0 -0
  19. {encommon-0.20.4 → encommon-0.21.0}/encommon/config/__init__.py +0 -0
  20. {encommon-0.20.4 → encommon-0.21.0}/encommon/config/config.py +0 -0
  21. {encommon-0.20.4 → encommon-0.21.0}/encommon/config/files.py +0 -0
  22. {encommon-0.20.4 → encommon-0.21.0}/encommon/config/logger.py +0 -0
  23. {encommon-0.20.4 → encommon-0.21.0}/encommon/config/params.py +0 -0
  24. {encommon-0.20.4 → encommon-0.21.0}/encommon/config/paths.py +0 -0
  25. {encommon-0.20.4 → encommon-0.21.0}/encommon/config/test/__init__.py +0 -0
  26. {encommon-0.20.4 → encommon-0.21.0}/encommon/config/test/test_config.py +0 -0
  27. {encommon-0.20.4 → encommon-0.21.0}/encommon/config/test/test_files.py +0 -0
  28. {encommon-0.20.4 → encommon-0.21.0}/encommon/config/test/test_logger.py +0 -0
  29. {encommon-0.20.4 → encommon-0.21.0}/encommon/config/test/test_paths.py +0 -0
  30. {encommon-0.20.4 → encommon-0.21.0}/encommon/config/test/test_utils.py +0 -0
  31. {encommon-0.20.4 → encommon-0.21.0}/encommon/config/utils.py +0 -0
  32. {encommon-0.20.4 → encommon-0.21.0}/encommon/conftest.py +0 -0
  33. {encommon-0.20.4 → encommon-0.21.0}/encommon/crypts/__init__.py +0 -0
  34. {encommon-0.20.4 → encommon-0.21.0}/encommon/crypts/crypts.py +0 -0
  35. {encommon-0.20.4 → encommon-0.21.0}/encommon/crypts/hashes.py +0 -0
  36. {encommon-0.20.4 → encommon-0.21.0}/encommon/crypts/params.py +0 -0
  37. {encommon-0.20.4 → encommon-0.21.0}/encommon/crypts/test/__init__.py +0 -0
  38. {encommon-0.20.4 → encommon-0.21.0}/encommon/crypts/test/test_crypts.py +0 -0
  39. {encommon-0.20.4 → encommon-0.21.0}/encommon/crypts/test/test_hashes.py +0 -0
  40. {encommon-0.20.4 → encommon-0.21.0}/encommon/parse/__init__.py +0 -0
  41. {encommon-0.20.4 → encommon-0.21.0}/encommon/parse/jinja2.py +0 -0
  42. {encommon-0.20.4 → encommon-0.21.0}/encommon/parse/network.py +0 -0
  43. {encommon-0.20.4 → encommon-0.21.0}/encommon/parse/test/__init__.py +0 -0
  44. {encommon-0.20.4 → encommon-0.21.0}/encommon/parse/test/test_jinja2.py +0 -0
  45. {encommon-0.20.4 → encommon-0.21.0}/encommon/parse/test/test_network.py +0 -0
  46. {encommon-0.20.4 → encommon-0.21.0}/encommon/py.typed +0 -0
  47. {encommon-0.20.4 → encommon-0.21.0}/encommon/times/__init__.py +0 -0
  48. {encommon-0.20.4 → encommon-0.21.0}/encommon/times/common.py +0 -0
  49. {encommon-0.20.4 → encommon-0.21.0}/encommon/times/duration.py +0 -0
  50. {encommon-0.20.4 → encommon-0.21.0}/encommon/times/params.py +0 -0
  51. {encommon-0.20.4 → encommon-0.21.0}/encommon/times/parse.py +0 -0
  52. {encommon-0.20.4 → encommon-0.21.0}/encommon/times/test/__init__.py +0 -0
  53. {encommon-0.20.4 → encommon-0.21.0}/encommon/times/test/test_duration.py +0 -0
  54. {encommon-0.20.4 → encommon-0.21.0}/encommon/times/test/test_params.py +0 -0
  55. {encommon-0.20.4 → encommon-0.21.0}/encommon/times/test/test_parse.py +0 -0
  56. {encommon-0.20.4 → encommon-0.21.0}/encommon/times/test/test_time.py +0 -0
  57. {encommon-0.20.4 → encommon-0.21.0}/encommon/times/test/test_timer.py +0 -0
  58. {encommon-0.20.4 → encommon-0.21.0}/encommon/times/test/test_timers.py +0 -0
  59. {encommon-0.20.4 → encommon-0.21.0}/encommon/times/test/test_unitime.py +0 -0
  60. {encommon-0.20.4 → encommon-0.21.0}/encommon/times/test/test_utils.py +0 -0
  61. {encommon-0.20.4 → encommon-0.21.0}/encommon/times/test/test_window.py +0 -0
  62. {encommon-0.20.4 → encommon-0.21.0}/encommon/times/test/test_windows.py +0 -0
  63. {encommon-0.20.4 → encommon-0.21.0}/encommon/times/time.py +0 -0
  64. {encommon-0.20.4 → encommon-0.21.0}/encommon/times/timer.py +0 -0
  65. {encommon-0.20.4 → encommon-0.21.0}/encommon/times/timers.py +0 -0
  66. {encommon-0.20.4 → encommon-0.21.0}/encommon/times/unitime.py +0 -0
  67. {encommon-0.20.4 → encommon-0.21.0}/encommon/times/utils.py +0 -0
  68. {encommon-0.20.4 → encommon-0.21.0}/encommon/times/window.py +0 -0
  69. {encommon-0.20.4 → encommon-0.21.0}/encommon/times/windows.py +0 -0
  70. {encommon-0.20.4 → encommon-0.21.0}/encommon/types/classes.py +0 -0
  71. {encommon-0.20.4 → encommon-0.21.0}/encommon/types/dicts.py +0 -0
  72. {encommon-0.20.4 → encommon-0.21.0}/encommon/types/empty.py +0 -0
  73. {encommon-0.20.4 → encommon-0.21.0}/encommon/types/lists.py +0 -0
  74. {encommon-0.20.4 → encommon-0.21.0}/encommon/types/strings.py +0 -0
  75. {encommon-0.20.4 → encommon-0.21.0}/encommon/types/test/test_classes.py +0 -0
  76. {encommon-0.20.4 → encommon-0.21.0}/encommon/types/test/test_empty.py +0 -0
  77. {encommon-0.20.4 → encommon-0.21.0}/encommon/types/test/test_lists.py +0 -0
  78. {encommon-0.20.4 → encommon-0.21.0}/encommon/types/test/test_strings.py +0 -0
  79. {encommon-0.20.4 → encommon-0.21.0}/encommon/types/types.py +0 -0
  80. {encommon-0.20.4 → encommon-0.21.0}/encommon/utils/__init__.py +0 -0
  81. {encommon-0.20.4 → encommon-0.21.0}/encommon/utils/common.py +0 -0
  82. {encommon-0.20.4 → encommon-0.21.0}/encommon/utils/files.py +0 -0
  83. {encommon-0.20.4 → encommon-0.21.0}/encommon/utils/match.py +0 -0
  84. {encommon-0.20.4 → encommon-0.21.0}/encommon/utils/paths.py +0 -0
  85. {encommon-0.20.4 → encommon-0.21.0}/encommon/utils/sample.py +0 -0
  86. {encommon-0.20.4 → encommon-0.21.0}/encommon/utils/stdout.py +0 -0
  87. {encommon-0.20.4 → encommon-0.21.0}/encommon/utils/test/__init__.py +0 -0
  88. {encommon-0.20.4 → encommon-0.21.0}/encommon/utils/test/test_files.py +0 -0
  89. {encommon-0.20.4 → encommon-0.21.0}/encommon/utils/test/test_match.py +0 -0
  90. {encommon-0.20.4 → encommon-0.21.0}/encommon/utils/test/test_paths.py +0 -0
  91. {encommon-0.20.4 → encommon-0.21.0}/encommon/utils/test/test_sample.py +0 -0
  92. {encommon-0.20.4 → encommon-0.21.0}/encommon/utils/test/test_stdout.py +0 -0
  93. {encommon-0.20.4 → encommon-0.21.0}/encommon.egg-info/SOURCES.txt +0 -0
  94. {encommon-0.20.4 → encommon-0.21.0}/encommon.egg-info/dependency_links.txt +0 -0
  95. {encommon-0.20.4 → encommon-0.21.0}/encommon.egg-info/requires.txt +0 -0
  96. {encommon-0.20.4 → encommon-0.21.0}/encommon.egg-info/top_level.txt +0 -0
  97. {encommon-0.20.4 → encommon-0.21.0}/pyproject.toml +0 -0
  98. {encommon-0.20.4 → encommon-0.21.0}/require/install.txt +0 -0
  99. {encommon-0.20.4 → encommon-0.21.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: encommon
3
- Version: 0.20.4
3
+ Version: 0.21.0
4
4
  Summary: Enasis Network Common Library
5
5
  License: MIT
6
6
  Project-URL: Source, https://github.com/enasisnetwork/encommon
@@ -30,6 +30,7 @@ Common classes and functions used in various public and private projects.
30
30
  <a href="https://pypi.org/project/encommon"><img src="https://enasisnetwork.github.io/encommon/badges/pypi.png"></a><br>
31
31
  <a href="https://enasisnetwork.github.io/encommon/validate/flake8.txt"><img src="https://enasisnetwork.github.io/encommon/badges/flake8.png"></a><br>
32
32
  <a href="https://enasisnetwork.github.io/encommon/validate/pylint.txt"><img src="https://enasisnetwork.github.io/encommon/badges/pylint.png"></a><br>
33
+ <a href="https://enasisnetwork.github.io/encommon/validate/ruff.txt"><img src="https://enasisnetwork.github.io/encommon/badges/ruff.png"></a><br>
33
34
  <a href="https://enasisnetwork.github.io/encommon/validate/mypy.txt"><img src="https://enasisnetwork.github.io/encommon/badges/mypy.png"></a><br>
34
35
  <a href="https://enasisnetwork.github.io/encommon/validate/yamllint.txt"><img src="https://enasisnetwork.github.io/encommon/badges/yamllint.png"></a><br>
35
36
  <a href="https://enasisnetwork.github.io/encommon/validate/pytest.txt"><img src="https://enasisnetwork.github.io/encommon/badges/pytest.png"></a><br>
@@ -7,6 +7,7 @@ Common classes and functions used in various public and private projects.
7
7
  <a href="https://pypi.org/project/encommon"><img src="https://enasisnetwork.github.io/encommon/badges/pypi.png"></a><br>
8
8
  <a href="https://enasisnetwork.github.io/encommon/validate/flake8.txt"><img src="https://enasisnetwork.github.io/encommon/badges/flake8.png"></a><br>
9
9
  <a href="https://enasisnetwork.github.io/encommon/validate/pylint.txt"><img src="https://enasisnetwork.github.io/encommon/badges/pylint.png"></a><br>
10
+ <a href="https://enasisnetwork.github.io/encommon/validate/ruff.txt"><img src="https://enasisnetwork.github.io/encommon/badges/ruff.png"></a><br>
10
11
  <a href="https://enasisnetwork.github.io/encommon/validate/mypy.txt"><img src="https://enasisnetwork.github.io/encommon/badges/mypy.png"></a><br>
11
12
  <a href="https://enasisnetwork.github.io/encommon/validate/yamllint.txt"><img src="https://enasisnetwork.github.io/encommon/badges/yamllint.png"></a><br>
12
13
  <a href="https://enasisnetwork.github.io/encommon/validate/pytest.txt"><img src="https://enasisnetwork.github.io/encommon/badges/pytest.png"></a><br>
@@ -192,7 +192,8 @@ class Color:
192
192
  if isinstance(other, str):
193
193
  other = Color(other)
194
194
 
195
- assert hasattr(other, 'source')
195
+ assert hasattr(
196
+ other, 'source')
196
197
 
197
198
  source = self.__source
198
199
  _source = other.source
@@ -237,7 +238,8 @@ class Color:
237
238
  if isinstance(other, str):
238
239
  other = Color(other)
239
240
 
240
- assert hasattr(other, 'source')
241
+ assert hasattr(
242
+ other, 'source')
241
243
 
242
244
  source = self.__source
243
245
  _source = other.source
@@ -268,7 +270,8 @@ class Color:
268
270
  if isinstance(other, str):
269
271
  other = Color(other)
270
272
 
271
- assert hasattr(other, 'source')
273
+ assert hasattr(
274
+ other, 'source')
272
275
 
273
276
  source = self.__source
274
277
  _source = other.source
@@ -299,7 +302,8 @@ class Color:
299
302
  if isinstance(other, str):
300
303
  other = Color(other)
301
304
 
302
- assert hasattr(other, 'source')
305
+ assert hasattr(
306
+ other, 'source')
303
307
 
304
308
  source = self.__source
305
309
  _source = other.source
@@ -330,7 +334,8 @@ class Color:
330
334
  if isinstance(other, str):
331
335
  other = Color(other)
332
336
 
333
- assert hasattr(other, 'source')
337
+ assert hasattr(
338
+ other, 'source')
334
339
 
335
340
  source = self.__source
336
341
  _source = other.source
@@ -45,7 +45,7 @@ def test_Color() -> None:
45
45
 
46
46
  assert color == '000001'
47
47
  assert color != '000000'
48
- assert color != int
48
+ assert color != int # noqa
49
49
 
50
50
  assert color > 0
51
51
  assert color >= 1
@@ -17,7 +17,9 @@ from .lists import dedup_list
17
17
  from .lists import fuzzy_list
18
18
  from .lists import inlist
19
19
  from .notate import delate
20
+ from .notate import expate
20
21
  from .notate import getate
22
+ from .notate import impate
21
23
  from .notate import setate
22
24
  from .strings import hasstr
23
25
  from .strings import inrepr
@@ -39,8 +41,10 @@ __all__ = [
39
41
  'delate',
40
42
  'DictStrAny',
41
43
  'Empty',
44
+ 'expate',
42
45
  'getate',
43
46
  'hasstr',
47
+ 'impate',
44
48
  'inlist',
45
49
  'inrepr',
46
50
  'instr',
@@ -193,6 +193,185 @@ def delate(
193
193
 
194
194
 
195
195
 
196
+ def impate( # noqa: CFQ001,CFQ004
197
+ source: DictStrAny | list[DictStrAny],
198
+ delim: str = '/',
199
+ parent: Optional[str] = None,
200
+ *,
201
+ implode_list: bool = True,
202
+ recurse_list: bool = True,
203
+ ) -> DictStrAny | list[DictStrAny]:
204
+ """
205
+ Implode the dictionary into a single depth of notation.
206
+
207
+ Example
208
+ -------
209
+ >>> impate({'foo': {'bar': 'baz'}})
210
+ {'foo/bar': 'baz'}
211
+
212
+ :param source: Dictionary object processed in notation.
213
+ :param delim: Override default delimiter between parts.
214
+ :param parent: Parent key prefix for downstream update.
215
+ :param implode_list: Determine whether list is imploded.
216
+ :param recurse_list: Determine whether flatten in list.
217
+ :returns: New dictionary that was recursively imploded.
218
+ It is also possible that a list of dictionary will
219
+ be returned when provided and implode_list is False.
220
+ """
221
+
222
+ _implode = implode_list
223
+ _recurse = recurse_list
224
+
225
+
226
+ def _proclist(
227
+ source: list[Any],
228
+ delim: str,
229
+ parent: Optional[str],
230
+ ) -> DictStrAny | list[Any]:
231
+
232
+
233
+ if _implode is False:
234
+
235
+ process = [
236
+ (impate(
237
+ item, delim,
238
+ implode_list=_implode,
239
+ recurse_list=_recurse)
240
+ if isinstance(item, dict | list)
241
+ and _recurse is True
242
+ else item)
243
+ for item in source]
244
+
245
+ return (
246
+ {parent: process}
247
+ if parent is not None
248
+ else process)
249
+
250
+
251
+ returned: DictStrAny = {}
252
+
253
+ for i, item in enumerate(source):
254
+
255
+ key = (
256
+ f'{parent}{delim}{i}'
257
+ if parent is not None
258
+ else str(i))
259
+
260
+ if (isinstance(item, dict | list)
261
+ and _recurse is True):
262
+
263
+ implode = impate(
264
+ item, delim, key,
265
+ implode_list=_implode,
266
+ recurse_list=_recurse)
267
+
268
+ assert isinstance(implode, dict)
269
+
270
+ returned.update(implode)
271
+
272
+ else:
273
+ returned[key] = item
274
+
275
+ return returned
276
+
277
+
278
+ def _procdict(
279
+ source: DictStrAny,
280
+ delim: str,
281
+ parent: Optional[str],
282
+ ) -> DictStrAny:
283
+
284
+ returned: DictStrAny = {}
285
+
286
+ for key, value in source.items():
287
+
288
+ key = (
289
+ f'{parent}{delim}{key}'
290
+ if parent is not None
291
+ else key)
292
+
293
+ if isinstance(value, dict):
294
+
295
+ implode = impate(
296
+ value, delim, key,
297
+ implode_list=_implode,
298
+ recurse_list=_recurse)
299
+
300
+ assert isinstance(implode, dict)
301
+
302
+ returned |= implode
303
+
304
+ elif isinstance(value, list):
305
+
306
+ process = _proclist(
307
+ value, delim, key)
308
+
309
+ returned |= (
310
+ {key: process}
311
+ if not isinstance(process, dict)
312
+ else process)
313
+
314
+ else:
315
+ returned[key] = value
316
+
317
+ return returned
318
+
319
+
320
+ if isinstance(source, dict):
321
+ return _procdict(
322
+ source, delim, parent)
323
+
324
+ if isinstance(source, list):
325
+ return _proclist(
326
+ source, delim, parent)
327
+
328
+ raise ValueError('source')
329
+
330
+
331
+
332
+ def expate(
333
+ source: DictStrAny,
334
+ delim: str = '/',
335
+ ) -> DictStrAny:
336
+ """
337
+ Explode the dictionary from a single depth of notation.
338
+
339
+ Example
340
+ -------
341
+ >>> expate({'foo/bar': 'baz'})
342
+ {'foo': {'bar': 'baz'}}
343
+
344
+ :param source: Dictionary object processed in notation.
345
+ :param delim: Override default delimiter between parts.
346
+ :returns: New dictionary that was recursively exploded.
347
+ """
348
+
349
+ returned: DictStrAny = {}
350
+
351
+
352
+ items = source.items()
353
+
354
+ for key, value in items:
355
+
356
+ if isinstance(value, list):
357
+ value = [
358
+ (expate(x, delim)
359
+ if isinstance(x, dict)
360
+ else x)
361
+ for x in value]
362
+
363
+ if isinstance(value, dict):
364
+ value = expate(value, delim)
365
+
366
+ setate(
367
+ returned, key,
368
+ value, delim)
369
+
370
+
371
+ return returned
372
+
373
+
374
+
196
375
  def _setpath(
197
376
  source: _SETABLE,
198
377
  path: str,
@@ -8,6 +8,13 @@ is permitted, for more information consult the project license file.
8
8
 
9
9
 
10
10
  from copy import deepcopy
11
+ from pathlib import Path
12
+
13
+
14
+
15
+ SAMPLES = (
16
+ Path(__file__).parent
17
+ / 'samples')
11
18
 
12
19
 
13
20
 
@@ -140,6 +140,7 @@ def test_merge_dicts() -> None: # noqa: CFQ001
140
140
  assert source is not _source
141
141
 
142
142
 
143
+
143
144
  def test_sort_dict() -> None:
144
145
  """
145
146
  Perform various tests associated with relevant routines.