encommon 0.4.0__tar.gz → 0.5.0__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.
- {encommon-0.4.0 → encommon-0.5.0}/LICENSE +1 -1
- {encommon-0.4.0/encommon.egg-info → encommon-0.5.0}/PKG-INFO +20 -15
- {encommon-0.4.0 → encommon-0.5.0}/README.md +19 -14
- {encommon-0.4.0 → encommon-0.5.0}/encommon/config/params.py +10 -0
- {encommon-0.4.0 → encommon-0.5.0}/encommon/config/test/test_config.py +21 -1
- {encommon-0.4.0 → encommon-0.5.0}/encommon/times/common.py +1 -1
- {encommon-0.4.0 → encommon-0.5.0}/encommon/times/duration.py +99 -43
- {encommon-0.4.0 → encommon-0.5.0}/encommon/times/test/test_duration.py +70 -17
- {encommon-0.4.0 → encommon-0.5.0}/encommon/types/__init__.py +5 -1
- {encommon-0.4.0 → encommon-0.5.0}/encommon/types/dicts.py +26 -0
- encommon-0.5.0/encommon/types/strings.py +25 -0
- {encommon-0.4.0 → encommon-0.5.0}/encommon/types/test/test_dicts.py +33 -13
- encommon-0.5.0/encommon/types/test/test_strings.py +19 -0
- {encommon-0.4.0 → encommon-0.5.0}/encommon/utils/sample.py +1 -1
- encommon-0.5.0/encommon/version.txt +1 -0
- {encommon-0.4.0 → encommon-0.5.0/encommon.egg-info}/PKG-INFO +20 -15
- {encommon-0.4.0 → encommon-0.5.0}/encommon.egg-info/SOURCES.txt +3 -1
- encommon-0.4.0/encommon/version.txt +0 -1
- {encommon-0.4.0 → encommon-0.5.0}/MANIFEST.in +0 -0
- {encommon-0.4.0 → encommon-0.5.0}/encommon/__init__.py +0 -0
- {encommon-0.4.0 → encommon-0.5.0}/encommon/config/__init__.py +0 -0
- {encommon-0.4.0 → encommon-0.5.0}/encommon/config/common.py +0 -0
- {encommon-0.4.0 → encommon-0.5.0}/encommon/config/config.py +0 -0
- {encommon-0.4.0 → encommon-0.5.0}/encommon/config/files.py +0 -0
- {encommon-0.4.0 → encommon-0.5.0}/encommon/config/logger.py +0 -0
- {encommon-0.4.0 → encommon-0.5.0}/encommon/config/paths.py +0 -0
- {encommon-0.4.0 → encommon-0.5.0}/encommon/config/test/__init__.py +0 -0
- {encommon-0.4.0 → encommon-0.5.0}/encommon/config/test/test_common.py +0 -0
- {encommon-0.4.0 → encommon-0.5.0}/encommon/config/test/test_files.py +0 -0
- {encommon-0.4.0 → encommon-0.5.0}/encommon/config/test/test_logger.py +0 -0
- {encommon-0.4.0 → encommon-0.5.0}/encommon/config/test/test_paths.py +0 -0
- {encommon-0.4.0/encommon/config/test → encommon-0.5.0/encommon}/conftest.py +0 -0
- {encommon-0.4.0 → encommon-0.5.0}/encommon/crypts/__init__.py +0 -0
- {encommon-0.4.0 → encommon-0.5.0}/encommon/crypts/crypts.py +0 -0
- {encommon-0.4.0 → encommon-0.5.0}/encommon/crypts/hashes.py +0 -0
- {encommon-0.4.0 → encommon-0.5.0}/encommon/crypts/params.py +0 -0
- {encommon-0.4.0 → encommon-0.5.0}/encommon/crypts/test/__init__.py +0 -0
- {encommon-0.4.0 → encommon-0.5.0}/encommon/crypts/test/test_crypts.py +0 -0
- {encommon-0.4.0 → encommon-0.5.0}/encommon/crypts/test/test_hashes.py +0 -0
- {encommon-0.4.0 → encommon-0.5.0}/encommon/py.typed +0 -0
- {encommon-0.4.0 → encommon-0.5.0}/encommon/times/__init__.py +0 -0
- {encommon-0.4.0 → encommon-0.5.0}/encommon/times/parse.py +0 -0
- {encommon-0.4.0 → encommon-0.5.0}/encommon/times/test/__init__.py +0 -0
- {encommon-0.4.0 → encommon-0.5.0}/encommon/times/test/test_common.py +0 -0
- {encommon-0.4.0 → encommon-0.5.0}/encommon/times/test/test_parse.py +0 -0
- {encommon-0.4.0 → encommon-0.5.0}/encommon/times/test/test_timers.py +0 -0
- {encommon-0.4.0 → encommon-0.5.0}/encommon/times/test/test_times.py +0 -0
- {encommon-0.4.0 → encommon-0.5.0}/encommon/times/test/test_window.py +0 -0
- {encommon-0.4.0 → encommon-0.5.0}/encommon/times/timers.py +1 -1
- {encommon-0.4.0 → encommon-0.5.0}/encommon/times/times.py +0 -0
- {encommon-0.4.0 → encommon-0.5.0}/encommon/times/window.py +0 -0
- {encommon-0.4.0 → encommon-0.5.0}/encommon/types/empty.py +0 -0
- {encommon-0.4.0 → encommon-0.5.0}/encommon/types/test/__init__.py +0 -0
- {encommon-0.4.0 → encommon-0.5.0}/encommon/types/test/test_empty.py +0 -0
- {encommon-0.4.0 → encommon-0.5.0}/encommon/utils/__init__.py +0 -0
- {encommon-0.4.0 → encommon-0.5.0}/encommon/utils/common.py +0 -0
- {encommon-0.4.0 → encommon-0.5.0}/encommon/utils/match.py +0 -0
- {encommon-0.4.0 → encommon-0.5.0}/encommon/utils/paths.py +0 -0
- {encommon-0.4.0 → encommon-0.5.0}/encommon/utils/stdout.py +0 -0
- {encommon-0.4.0 → encommon-0.5.0}/encommon/utils/test/__init__.py +0 -0
- {encommon-0.4.0 → encommon-0.5.0}/encommon/utils/test/test_match.py +0 -0
- {encommon-0.4.0 → encommon-0.5.0}/encommon/utils/test/test_paths.py +0 -0
- {encommon-0.4.0 → encommon-0.5.0}/encommon/utils/test/test_sample.py +0 -0
- {encommon-0.4.0 → encommon-0.5.0}/encommon/utils/test/test_stdout.py +0 -0
- {encommon-0.4.0 → encommon-0.5.0}/encommon.egg-info/dependency_links.txt +0 -0
- {encommon-0.4.0 → encommon-0.5.0}/encommon.egg-info/requires.txt +0 -0
- {encommon-0.4.0 → encommon-0.5.0}/encommon.egg-info/top_level.txt +0 -0
- {encommon-0.4.0 → encommon-0.5.0}/pyproject.toml +0 -0
- {encommon-0.4.0 → encommon-0.5.0}/reqs-install.txt +0 -0
- {encommon-0.4.0 → encommon-0.5.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: encommon
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.5.0
|
4
4
|
Summary: Enasis Network Common Library
|
5
5
|
License: MIT
|
6
6
|
Classifier: Programming Language :: Python :: 3
|
@@ -18,14 +18,15 @@ Requires-Dist: snaptime
|
|
18
18
|
|
19
19
|
# Enasis Network Common Library
|
20
20
|
|
21
|
-
[](https://github.com/enasisnetwork/encommon/actions)
|
22
|
-
[](https://encommon.readthedocs.io/en/stable)
|
23
|
-
[](https://pypi.org/project/encommon)
|
24
|
-
[](https://pypi.org/project/encommon)
|
25
|
-
|
26
21
|
Common classes and functions used in various public and private projects for
|
27
22
|
[Enasis Network](https://github.com/enasisnetwork).
|
28
23
|
|
24
|
+
[](https://github.com/enasisnetwork/encommon/actions)<br>
|
25
|
+
[](https://codecov.io/gh/enasisnetwork/encommon)<br>
|
26
|
+
[](https://encommon.readthedocs.io/en/stable)<br>
|
27
|
+
[](https://pypi.org/project/encommon)<br>
|
28
|
+
[](https://pypi.org/project/encommon)
|
29
|
+
|
29
30
|
## Installing the package
|
30
31
|
Installing stable from the PyPi repository
|
31
32
|
```
|
@@ -67,12 +68,16 @@ information found in the `htmlcov` folder in the root of the project.
|
|
67
68
|
make -s pytest
|
68
69
|
```
|
69
70
|
|
70
|
-
##
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
71
|
+
## Build and upload to PyPi
|
72
|
+
Build the package.
|
73
|
+
```
|
74
|
+
make -s pypackage
|
75
|
+
```
|
76
|
+
Upload to the test PyPi.
|
77
|
+
```
|
78
|
+
make -s pypi-upload-test
|
79
|
+
```
|
80
|
+
Upload to the prod PyPi.
|
81
|
+
```
|
82
|
+
make -s pypi-upload-prod
|
83
|
+
```
|
@@ -1,13 +1,14 @@
|
|
1
1
|
# Enasis Network Common Library
|
2
2
|
|
3
|
-
[](https://github.com/enasisnetwork/encommon/actions)
|
4
|
-
[](https://encommon.readthedocs.io/en/stable)
|
5
|
-
[](https://pypi.org/project/encommon)
|
6
|
-
[](https://pypi.org/project/encommon)
|
7
|
-
|
8
3
|
Common classes and functions used in various public and private projects for
|
9
4
|
[Enasis Network](https://github.com/enasisnetwork).
|
10
5
|
|
6
|
+
[](https://github.com/enasisnetwork/encommon/actions)<br>
|
7
|
+
[](https://codecov.io/gh/enasisnetwork/encommon)<br>
|
8
|
+
[](https://encommon.readthedocs.io/en/stable)<br>
|
9
|
+
[](https://pypi.org/project/encommon)<br>
|
10
|
+
[](https://pypi.org/project/encommon)
|
11
|
+
|
11
12
|
## Installing the package
|
12
13
|
Installing stable from the PyPi repository
|
13
14
|
```
|
@@ -49,12 +50,16 @@ information found in the `htmlcov` folder in the root of the project.
|
|
49
50
|
make -s pytest
|
50
51
|
```
|
51
52
|
|
52
|
-
##
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
53
|
+
## Build and upload to PyPi
|
54
|
+
Build the package.
|
55
|
+
```
|
56
|
+
make -s pypackage
|
57
|
+
```
|
58
|
+
Upload to the test PyPi.
|
59
|
+
```
|
60
|
+
make -s pypi-upload-test
|
61
|
+
```
|
62
|
+
Upload to the prod PyPi.
|
63
|
+
```
|
64
|
+
make -s pypi-upload-prod
|
65
|
+
```
|
@@ -20,7 +20,9 @@ class ConfigParams(BaseModel, extra='forbid'):
|
|
20
20
|
"""
|
21
21
|
Process and validate the common configuration parameters.
|
22
22
|
|
23
|
+
:param paths: Complete or relative path to config paths.
|
23
24
|
:param data: Keyword arguments passed to Pydantic model.
|
25
|
+
This parameter is picked up by autodoc, please ignore.
|
24
26
|
"""
|
25
27
|
|
26
28
|
paths: Optional[list[str]] = None
|
@@ -31,7 +33,11 @@ class LoggerParams(BaseModel, extra='forbid'):
|
|
31
33
|
"""
|
32
34
|
Process and validate the common configuration parameters.
|
33
35
|
|
36
|
+
:param stdo_level: Minimum log message severity level.
|
37
|
+
:param file_level: Minimum log message severity level.
|
38
|
+
:param file_path: Enables writing to the filesystem path.
|
34
39
|
:param data: Keyword arguments passed to Pydantic model.
|
40
|
+
This parameter is picked up by autodoc, please ignore.
|
35
41
|
"""
|
36
42
|
|
37
43
|
stdo_level: Optional[LOGLEVELS] = None
|
@@ -44,7 +50,11 @@ class Params(BaseModel, extra='forbid'):
|
|
44
50
|
"""
|
45
51
|
Process and validate the common configuration parameters.
|
46
52
|
|
53
|
+
:param enconfig: Configuration for the `.Config` object.
|
54
|
+
:param enlogger: Configuration for the `.Logger` object.
|
55
|
+
:param encrypts: Configuration for the `.Crypts` object.
|
47
56
|
:param data: Keyword arguments passed to Pydantic model.
|
57
|
+
This parameter is picked up by autodoc, please ignore.
|
48
58
|
"""
|
49
59
|
|
50
60
|
enconfig: Optional[ConfigParams] = None
|
@@ -25,7 +25,7 @@ SAMPLES = (
|
|
25
25
|
|
26
26
|
|
27
27
|
|
28
|
-
def test_Config(
|
28
|
+
def test_Config( # noqa: CFQ001
|
29
29
|
config_path: Path,
|
30
30
|
) -> None:
|
31
31
|
"""
|
@@ -108,6 +108,26 @@ def test_Config(
|
|
108
108
|
assert sample == expect
|
109
109
|
|
110
110
|
|
111
|
+
_params1 = config.params
|
112
|
+
_params2 = config.params
|
113
|
+
|
114
|
+
assert _params1 is _params2
|
115
|
+
|
116
|
+
sample = load_sample(
|
117
|
+
path=SAMPLES.joinpath('params.json'),
|
118
|
+
update=ENPYRWS,
|
119
|
+
content=_params1.model_dump(),
|
120
|
+
replace={
|
121
|
+
'config_path': str(config_path)})
|
122
|
+
|
123
|
+
expect = prep_sample(
|
124
|
+
content=_params2.model_dump(),
|
125
|
+
replace={
|
126
|
+
'config_path': str(config_path)})
|
127
|
+
|
128
|
+
assert sample == expect
|
129
|
+
|
130
|
+
|
111
131
|
logger = config.logger
|
112
132
|
|
113
133
|
assert isinstance(logger, Logger)
|
@@ -9,6 +9,7 @@ is permitted, for more information consult the project license file.
|
|
9
9
|
|
10
10
|
from typing import Literal
|
11
11
|
from typing import Union
|
12
|
+
from typing import get_args
|
12
13
|
|
13
14
|
|
14
15
|
|
@@ -17,14 +18,16 @@ DURAGROUP = Literal[
|
|
17
18
|
'day', 'hour', 'minute',
|
18
19
|
'second']
|
19
20
|
|
20
|
-
DURASHORT =
|
21
|
-
'
|
22
|
-
'
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
21
|
+
DURASHORT = Literal[
|
22
|
+
'y', 'mon', 'w',
|
23
|
+
'd', 'h', 'm', 's']
|
24
|
+
|
25
|
+
DURAMAPS = dict(zip(
|
26
|
+
get_args(DURAGROUP),
|
27
|
+
get_args(DURASHORT)))
|
28
|
+
|
29
|
+
DURAUNITS = Union[
|
30
|
+
DURAGROUP, DURASHORT]
|
28
31
|
|
29
32
|
|
30
33
|
|
@@ -49,16 +52,20 @@ class Duration:
|
|
49
52
|
|
50
53
|
:param seconds: Period in seconds that will be iterated.
|
51
54
|
:param smart: Determines if we hide seconds after minute.
|
55
|
+
:param groups: Determine the amount of groups to show,
|
56
|
+
ensuring the larger units are returned before smaller.
|
52
57
|
"""
|
53
58
|
|
54
59
|
__source: float
|
55
60
|
__smart: bool
|
61
|
+
__groups: int
|
56
62
|
|
57
63
|
|
58
64
|
def __init__(
|
59
65
|
self,
|
60
66
|
seconds: int | float,
|
61
67
|
smart: bool = True,
|
68
|
+
groups: int = len(DURAMAPS),
|
62
69
|
) -> None:
|
63
70
|
"""
|
64
71
|
Initialize instance for class using provided parameters.
|
@@ -66,6 +73,7 @@ class Duration:
|
|
66
73
|
|
67
74
|
self.__source = float(seconds)
|
68
75
|
self.__smart = bool(smart)
|
76
|
+
self.__groups = int(groups)
|
69
77
|
|
70
78
|
|
71
79
|
def __repr__(
|
@@ -77,7 +85,11 @@ class Duration:
|
|
77
85
|
:returns: String representation for values from instance.
|
78
86
|
"""
|
79
87
|
|
80
|
-
return
|
88
|
+
return (
|
89
|
+
f'Duration('
|
90
|
+
f'seconds={self.source}, '
|
91
|
+
f'smart={self.smart}, '
|
92
|
+
f'groups={self.groups})')
|
81
93
|
|
82
94
|
|
83
95
|
def __hash__(
|
@@ -290,16 +302,31 @@ class Duration:
|
|
290
302
|
@property
|
291
303
|
def groups(
|
292
304
|
self,
|
293
|
-
) ->
|
305
|
+
) -> int:
|
306
|
+
"""
|
307
|
+
Return the property for attribute from the class instance.
|
308
|
+
|
309
|
+
:returns: Property for attribute from the class instance.
|
310
|
+
"""
|
311
|
+
|
312
|
+
return self.__groups
|
313
|
+
|
314
|
+
|
315
|
+
def units(
|
316
|
+
self,
|
317
|
+
short: bool = False,
|
318
|
+
) -> dict[DURAUNITS, int]:
|
294
319
|
"""
|
295
320
|
Return the groups of time units with each relevant value.
|
296
321
|
|
322
|
+
:param short: Determine if we should use the short hand.
|
297
323
|
:returns: Groups of time units with each relevant value.
|
298
324
|
"""
|
299
325
|
|
300
|
-
|
326
|
+
source = self.__source
|
327
|
+
seconds = int(source)
|
301
328
|
|
302
|
-
returned: dict[
|
329
|
+
returned: dict[DURAUNITS, int] = {}
|
303
330
|
|
304
331
|
groups: dict[DURAGROUP, int] = {
|
305
332
|
'year': 31536000,
|
@@ -309,6 +336,7 @@ class Duration:
|
|
309
336
|
'hour': 3600,
|
310
337
|
'minute': 60}
|
311
338
|
|
339
|
+
|
312
340
|
for key, value in groups.items():
|
313
341
|
|
314
342
|
if seconds < value:
|
@@ -320,71 +348,99 @@ class Duration:
|
|
320
348
|
|
321
349
|
seconds %= value
|
322
350
|
|
323
|
-
|
351
|
+
|
352
|
+
if (source < 60
|
353
|
+
or (seconds >= 1
|
354
|
+
and source > 60)):
|
324
355
|
returned['second'] = seconds
|
325
356
|
|
326
|
-
|
357
|
+
if (self.__smart
|
358
|
+
and 'second' in returned
|
359
|
+
and len(returned) >= 2):
|
360
|
+
del returned['second']
|
327
361
|
|
328
362
|
|
329
|
-
|
330
|
-
|
363
|
+
items = (
|
364
|
+
list(returned.items())
|
365
|
+
[:self.__groups])
|
366
|
+
|
367
|
+
if short is False:
|
368
|
+
return dict(items)
|
369
|
+
|
370
|
+
return {
|
371
|
+
DURAMAPS[k]: v
|
372
|
+
for k, v in items}
|
373
|
+
|
374
|
+
|
375
|
+
def __duration(
|
331
376
|
self,
|
377
|
+
delim: str = ' ',
|
378
|
+
short: bool = True,
|
332
379
|
) -> str:
|
333
380
|
"""
|
334
381
|
Return the compact format calculated from source duration.
|
335
382
|
|
383
|
+
:param delim: Optional delimiter for between the groups.
|
384
|
+
:param short: Determine if we should use the short hand.
|
336
385
|
:returns: Compact format calculated from source duration.
|
337
386
|
"""
|
338
387
|
|
339
388
|
parts: list[str] = []
|
340
389
|
|
341
|
-
|
342
|
-
|
390
|
+
groups = self.units(short)
|
391
|
+
spaced = '' if short else ' '
|
343
392
|
|
344
393
|
for part, value in groups.items():
|
345
394
|
|
346
|
-
|
347
|
-
and self.__smart
|
348
|
-
and source >= 60):
|
349
|
-
continue
|
395
|
+
unit: str = part
|
350
396
|
|
351
|
-
|
397
|
+
if (short is False
|
398
|
+
and value != 1):
|
399
|
+
unit += 's'
|
352
400
|
|
353
|
-
parts.append(
|
401
|
+
parts.append(
|
402
|
+
f'{value}{spaced}{unit}')
|
354
403
|
|
355
|
-
return
|
404
|
+
return delim.join(parts)
|
356
405
|
|
357
406
|
|
358
407
|
@property
|
359
|
-
def
|
408
|
+
def short(
|
360
409
|
self,
|
361
410
|
) -> str:
|
362
411
|
"""
|
363
|
-
Return the
|
412
|
+
Return the compact format calculated from source duration.
|
364
413
|
|
365
414
|
:returns: Compact format calculated from source duration.
|
366
415
|
"""
|
367
416
|
|
368
|
-
|
417
|
+
return self.__duration()
|
369
418
|
|
370
|
-
source = self.__source
|
371
|
-
groups = self.groups
|
372
419
|
|
373
|
-
|
374
|
-
|
420
|
+
@property
|
421
|
+
def compact(
|
422
|
+
self,
|
423
|
+
) -> str:
|
424
|
+
"""
|
425
|
+
Return the compact format calculated from source duration.
|
375
426
|
|
376
|
-
|
427
|
+
:returns: Compact format calculated from source duration.
|
428
|
+
"""
|
377
429
|
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
430
|
+
return self.short.replace(' ', '')
|
431
|
+
|
432
|
+
|
433
|
+
@property
|
434
|
+
def verbose(
|
435
|
+
self,
|
436
|
+
) -> str:
|
437
|
+
"""
|
438
|
+
Return the verbose format calculated from source duration.
|
382
439
|
|
383
|
-
|
384
|
-
|
385
|
-
if value != 1
|
386
|
-
else part)
|
440
|
+
:returns: Compact format calculated from source duration.
|
441
|
+
"""
|
387
442
|
|
388
|
-
|
443
|
+
if self.__source < 60:
|
444
|
+
return 'just now'
|
389
445
|
|
390
|
-
return ', '
|
446
|
+
return self.__duration(', ', False)
|
@@ -16,44 +16,97 @@ def test_Duration() -> None:
|
|
16
16
|
Perform various tests associated with relevant routines.
|
17
17
|
"""
|
18
18
|
|
19
|
-
duration = Duration(
|
19
|
+
duration = Duration(95401)
|
20
20
|
|
21
21
|
attrs = list(duration.__dict__)
|
22
22
|
|
23
23
|
assert attrs == [
|
24
24
|
'_Duration__source',
|
25
|
-
'_Duration__smart'
|
25
|
+
'_Duration__smart',
|
26
|
+
'_Duration__groups']
|
26
27
|
|
27
28
|
|
28
29
|
assert repr(duration) == (
|
29
|
-
'Duration(
|
30
|
+
'Duration('
|
31
|
+
'seconds=95401.0, '
|
32
|
+
'smart=True, '
|
33
|
+
'groups=7)')
|
34
|
+
|
30
35
|
assert isinstance(hash(duration), int)
|
31
|
-
assert str(duration) == '
|
36
|
+
assert str(duration) == '1d2h30m'
|
32
37
|
|
33
38
|
|
34
|
-
assert int(duration) ==
|
35
|
-
assert float(duration) ==
|
39
|
+
assert int(duration) == 95401
|
40
|
+
assert float(duration) == 95401
|
36
41
|
|
37
|
-
assert duration + 1 ==
|
38
|
-
assert duration + duration ==
|
39
|
-
assert duration - 1 ==
|
42
|
+
assert duration + 1 == 95402
|
43
|
+
assert duration + duration == 190802
|
44
|
+
assert duration - 1 == 95400
|
40
45
|
assert duration - duration == 0
|
41
46
|
|
42
47
|
assert duration == duration
|
43
|
-
assert duration != Duration(
|
48
|
+
assert duration != Duration(60)
|
44
49
|
assert duration != 'invalid'
|
45
50
|
|
46
|
-
assert duration > Duration(
|
47
|
-
assert duration >= Duration(
|
48
|
-
assert duration < Duration(
|
49
|
-
assert duration <= Duration(
|
51
|
+
assert duration > Duration(95400)
|
52
|
+
assert duration >= Duration(95401)
|
53
|
+
assert duration < Duration(95402)
|
54
|
+
assert duration <= Duration(95401)
|
50
55
|
|
51
56
|
|
52
|
-
assert duration.source ==
|
57
|
+
assert duration.source == 95401
|
53
58
|
assert duration.smart is True
|
59
|
+
assert duration.groups == 7
|
60
|
+
|
61
|
+
assert duration.short == '1d 2h 30m'
|
62
|
+
assert duration.compact == '1d2h30m'
|
63
|
+
assert duration.verbose == (
|
64
|
+
'1 day, 2 hours, 30 minutes')
|
65
|
+
|
66
|
+
assert duration.units() == {
|
67
|
+
'day': 1,
|
68
|
+
'hour': 2,
|
69
|
+
'minute': 30}
|
70
|
+
|
71
|
+
|
72
|
+
duration = Duration(
|
73
|
+
seconds=7501,
|
74
|
+
smart=False)
|
75
|
+
|
76
|
+
assert duration.short == '2h 5m 1s'
|
77
|
+
assert duration.compact == '2h5m1s'
|
78
|
+
assert duration.verbose == (
|
79
|
+
'2 hours, 5 minutes, 1 second')
|
80
|
+
|
81
|
+
|
82
|
+
duration = Duration(
|
83
|
+
seconds=694800,
|
84
|
+
smart=False,
|
85
|
+
groups=3)
|
86
|
+
|
87
|
+
assert duration.short == '1w 1d 1h'
|
88
|
+
assert duration.compact == '1w1d1h'
|
89
|
+
assert duration.verbose == (
|
90
|
+
'1 week, 1 day, 1 hour')
|
91
|
+
|
92
|
+
|
93
|
+
duration = Duration(36295261)
|
94
|
+
|
95
|
+
assert duration.units() == {
|
96
|
+
'year': 1,
|
97
|
+
'week': 3,
|
98
|
+
'month': 1,
|
99
|
+
'day': 4,
|
100
|
+
'hour': 2,
|
101
|
+
'minute': 1}
|
54
102
|
|
55
|
-
assert duration.
|
56
|
-
|
103
|
+
assert duration.units(True) == {
|
104
|
+
'y': 1,
|
105
|
+
'w': 3,
|
106
|
+
'mon': 1,
|
107
|
+
'd': 4,
|
108
|
+
'h': 2,
|
109
|
+
'm': 1}
|
57
110
|
|
58
111
|
|
59
112
|
|
@@ -8,10 +8,14 @@ is permitted, for more information consult the project license file.
|
|
8
8
|
|
9
9
|
|
10
10
|
from .dicts import merge_dicts
|
11
|
+
from .dicts import sort_dict
|
11
12
|
from .empty import Empty
|
13
|
+
from .strings import striplower
|
12
14
|
|
13
15
|
|
14
16
|
|
15
17
|
__all__ = [
|
16
18
|
'Empty',
|
17
|
-
'merge_dicts'
|
19
|
+
'merge_dicts',
|
20
|
+
'sort_dict',
|
21
|
+
'striplower']
|
@@ -58,3 +58,29 @@ def merge_dicts(
|
|
58
58
|
|
59
59
|
elif force is True:
|
60
60
|
dict1[key] = value
|
61
|
+
|
62
|
+
|
63
|
+
|
64
|
+
def sort_dict(
|
65
|
+
value: dict[Any, Any],
|
66
|
+
reverse: bool = False,
|
67
|
+
) -> dict[Any, Any]:
|
68
|
+
"""
|
69
|
+
Sort the keys within the dictionary and return new one.
|
70
|
+
|
71
|
+
Example
|
72
|
+
-------
|
73
|
+
>>> foo = {'b': 'be', 'a': 'ey'}
|
74
|
+
>>> sort_dict(foo)
|
75
|
+
{'a': 'ey', 'b': 'be'}
|
76
|
+
>>> sort_dict(foo, True)
|
77
|
+
{'b': 'be', 'a': 'ey'}
|
78
|
+
|
79
|
+
:param value: Dictionary whose keys are sorted into new.
|
80
|
+
:param reverse: Optionally reverse the sort direction.
|
81
|
+
:returns: New dictionary with keys sorted alphabetical.
|
82
|
+
"""
|
83
|
+
|
84
|
+
return dict(sorted(
|
85
|
+
value.items(),
|
86
|
+
reverse=reverse))
|
@@ -0,0 +1,25 @@
|
|
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
|
+
def striplower(
|
11
|
+
value: str,
|
12
|
+
) -> str:
|
13
|
+
"""
|
14
|
+
Return the provided string but stripped and lower cased.
|
15
|
+
|
16
|
+
Example
|
17
|
+
-------
|
18
|
+
>>> striplower(' Foo ')
|
19
|
+
'foo'
|
20
|
+
|
21
|
+
:param value: String which will be stripped and lowered.
|
22
|
+
:returns: Provided string but stripped and lower cased.
|
23
|
+
"""
|
24
|
+
|
25
|
+
return value.strip().lower()
|
@@ -10,6 +10,23 @@ is permitted, for more information consult the project license file.
|
|
10
10
|
from copy import deepcopy
|
11
11
|
|
12
12
|
from ..dicts import merge_dicts
|
13
|
+
from ..dicts import sort_dict
|
14
|
+
|
15
|
+
|
16
|
+
|
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}
|
13
30
|
|
14
31
|
|
15
32
|
|
@@ -18,19 +35,8 @@ def test_merge_dicts() -> None:
|
|
18
35
|
Perform various tests associated with relevant routines.
|
19
36
|
"""
|
20
37
|
|
21
|
-
dict1 =
|
22
|
-
|
23
|
-
'str': 'd1string',
|
24
|
-
'list': ['d1list'],
|
25
|
-
'dict': {'key': 'd1value'},
|
26
|
-
'bool': False}
|
27
|
-
|
28
|
-
dict2 = {
|
29
|
-
'dict2': 'dict2',
|
30
|
-
'str': 'd2string',
|
31
|
-
'list': ['d2list'],
|
32
|
-
'dict': {'key': 'd2value'},
|
33
|
-
'bool': True}
|
38
|
+
dict1 = deepcopy(DICT1)
|
39
|
+
dict2 = deepcopy(DICT2)
|
34
40
|
|
35
41
|
dict1['recurse'] = deepcopy(dict1)
|
36
42
|
dict2['recurse'] = deepcopy(dict2)
|
@@ -100,3 +106,17 @@ def test_merge_dicts() -> None:
|
|
100
106
|
'list': ['d1list'],
|
101
107
|
'dict': {'key': 'd1value'},
|
102
108
|
'bool': False}}
|
109
|
+
|
110
|
+
|
111
|
+
|
112
|
+
def test_sort_dict() -> None:
|
113
|
+
"""
|
114
|
+
Perform various tests associated with relevant routines.
|
115
|
+
"""
|
116
|
+
|
117
|
+
assert sort_dict(DICT1) == {
|
118
|
+
'bool': False,
|
119
|
+
'dict': {'key': 'd1value'},
|
120
|
+
'dict1': 'dict1',
|
121
|
+
'list': ['d1list'],
|
122
|
+
'str': 'd1string'}
|
@@ -0,0 +1,19 @@
|
|
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 ..strings import striplower
|
11
|
+
|
12
|
+
|
13
|
+
|
14
|
+
def test_striplower() -> None:
|
15
|
+
"""
|
16
|
+
Perform various tests associated with relevant routines.
|
17
|
+
"""
|
18
|
+
|
19
|
+
assert striplower(' Foo ') == 'foo'
|
@@ -98,7 +98,7 @@ def load_sample(
|
|
98
98
|
:param update: Determine whether the sample is updated.
|
99
99
|
:param content: Content which will be processed for JSON.
|
100
100
|
:param default: Callable used when stringifying values.
|
101
|
-
:param replace: Optional string values to replace in
|
101
|
+
:param replace: Optional string values to replace in file.
|
102
102
|
:returns: Content after processing using JSON functions.
|
103
103
|
"""
|
104
104
|
|
@@ -0,0 +1 @@
|
|
1
|
+
0.5.0
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: encommon
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.5.0
|
4
4
|
Summary: Enasis Network Common Library
|
5
5
|
License: MIT
|
6
6
|
Classifier: Programming Language :: Python :: 3
|
@@ -18,14 +18,15 @@ Requires-Dist: snaptime
|
|
18
18
|
|
19
19
|
# Enasis Network Common Library
|
20
20
|
|
21
|
-
[](https://github.com/enasisnetwork/encommon/actions)
|
22
|
-
[](https://encommon.readthedocs.io/en/stable)
|
23
|
-
[](https://pypi.org/project/encommon)
|
24
|
-
[](https://pypi.org/project/encommon)
|
25
|
-
|
26
21
|
Common classes and functions used in various public and private projects for
|
27
22
|
[Enasis Network](https://github.com/enasisnetwork).
|
28
23
|
|
24
|
+
[](https://github.com/enasisnetwork/encommon/actions)<br>
|
25
|
+
[](https://codecov.io/gh/enasisnetwork/encommon)<br>
|
26
|
+
[](https://encommon.readthedocs.io/en/stable)<br>
|
27
|
+
[](https://pypi.org/project/encommon)<br>
|
28
|
+
[](https://pypi.org/project/encommon)
|
29
|
+
|
29
30
|
## Installing the package
|
30
31
|
Installing stable from the PyPi repository
|
31
32
|
```
|
@@ -67,12 +68,16 @@ information found in the `htmlcov` folder in the root of the project.
|
|
67
68
|
make -s pytest
|
68
69
|
```
|
69
70
|
|
70
|
-
##
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
71
|
+
## Build and upload to PyPi
|
72
|
+
Build the package.
|
73
|
+
```
|
74
|
+
make -s pypackage
|
75
|
+
```
|
76
|
+
Upload to the test PyPi.
|
77
|
+
```
|
78
|
+
make -s pypi-upload-test
|
79
|
+
```
|
80
|
+
Upload to the prod PyPi.
|
81
|
+
```
|
82
|
+
make -s pypi-upload-prod
|
83
|
+
```
|
@@ -5,6 +5,7 @@ pyproject.toml
|
|
5
5
|
reqs-install.txt
|
6
6
|
setup.cfg
|
7
7
|
encommon/__init__.py
|
8
|
+
encommon/conftest.py
|
8
9
|
encommon/py.typed
|
9
10
|
encommon/version.txt
|
10
11
|
encommon.egg-info/PKG-INFO
|
@@ -20,7 +21,6 @@ encommon/config/logger.py
|
|
20
21
|
encommon/config/params.py
|
21
22
|
encommon/config/paths.py
|
22
23
|
encommon/config/test/__init__.py
|
23
|
-
encommon/config/test/conftest.py
|
24
24
|
encommon/config/test/test_common.py
|
25
25
|
encommon/config/test/test_config.py
|
26
26
|
encommon/config/test/test_files.py
|
@@ -50,9 +50,11 @@ encommon/times/test/test_window.py
|
|
50
50
|
encommon/types/__init__.py
|
51
51
|
encommon/types/dicts.py
|
52
52
|
encommon/types/empty.py
|
53
|
+
encommon/types/strings.py
|
53
54
|
encommon/types/test/__init__.py
|
54
55
|
encommon/types/test/test_dicts.py
|
55
56
|
encommon/types/test/test_empty.py
|
57
|
+
encommon/types/test/test_strings.py
|
56
58
|
encommon/utils/__init__.py
|
57
59
|
encommon/utils/common.py
|
58
60
|
encommon/utils/match.py
|
@@ -1 +0,0 @@
|
|
1
|
-
0.4.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
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -130,8 +130,8 @@ class Timers:
|
|
130
130
|
Update the existing timer from mapping within the cache.
|
131
131
|
|
132
132
|
:param unique: Unique identifier for the timer in mapping.
|
133
|
-
:param started: Determines when the time starts for timer.
|
134
133
|
:param minimum: Determines minimum seconds that must pass.
|
134
|
+
:param started: Determines when the time starts for timer.
|
135
135
|
"""
|
136
136
|
|
137
137
|
timer = self.__timing
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|