encommon 0.13.0__py3-none-any.whl → 0.14.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.
Files changed (48) hide show
  1. encommon/__init__.py +2 -7
  2. encommon/colors/__init__.py +14 -0
  3. encommon/colors/colors.py +518 -0
  4. encommon/colors/test/__init__.py +6 -0
  5. encommon/colors/test/test_colors.py +189 -0
  6. encommon/config/config.py +73 -20
  7. encommon/config/files.py +3 -0
  8. encommon/config/logger.py +5 -0
  9. encommon/config/params.py +1 -2
  10. encommon/config/paths.py +3 -0
  11. encommon/config/test/test_config.py +5 -1
  12. encommon/config/test/test_logger.py +13 -8
  13. encommon/config/test/test_paths.py +1 -1
  14. encommon/config/utils.py +7 -1
  15. encommon/conftest.py +33 -22
  16. encommon/crypts/params.py +23 -4
  17. encommon/times/__init__.py +3 -1
  18. encommon/times/common.py +2 -1
  19. encommon/times/params.py +38 -8
  20. encommon/times/parse.py +37 -10
  21. encommon/times/test/test_parse.py +16 -9
  22. encommon/times/test/test_times.py +35 -2
  23. encommon/times/test/test_unitime.py +23 -0
  24. encommon/times/timers.py +6 -0
  25. encommon/times/times.py +71 -13
  26. encommon/times/unitime.py +48 -0
  27. encommon/times/windows.py +6 -0
  28. encommon/types/__init__.py +20 -2
  29. encommon/types/classes.py +97 -0
  30. encommon/types/lists.py +27 -0
  31. encommon/types/strings.py +29 -4
  32. encommon/types/test/test_classes.py +74 -0
  33. encommon/types/test/test_lists.py +23 -0
  34. encommon/types/test/test_strings.py +15 -3
  35. encommon/types/types.py +20 -0
  36. encommon/utils/__init__.py +4 -0
  37. encommon/utils/paths.py +5 -6
  38. encommon/utils/sample.py +117 -41
  39. encommon/utils/stdout.py +51 -5
  40. encommon/utils/test/test_sample.py +127 -28
  41. encommon/utils/test/test_stdout.py +91 -27
  42. encommon/version.txt +1 -1
  43. {encommon-0.13.0.dist-info → encommon-0.14.0.dist-info}/METADATA +1 -1
  44. encommon-0.14.0.dist-info/RECORD +84 -0
  45. {encommon-0.13.0.dist-info → encommon-0.14.0.dist-info}/WHEEL +1 -1
  46. encommon-0.13.0.dist-info/RECORD +0 -73
  47. {encommon-0.13.0.dist-info → encommon-0.14.0.dist-info}/LICENSE +0 -0
  48. {encommon-0.13.0.dist-info → encommon-0.14.0.dist-info}/top_level.txt +0 -0
encommon/times/params.py CHANGED
@@ -10,11 +10,15 @@ is permitted, for more information consult the project license file.
10
10
  from typing import Any
11
11
  from typing import Optional
12
12
 
13
- from pydantic import BaseModel
14
-
15
13
  from .common import PARSABLE
16
14
  from .common import SCHEDULE
17
15
  from .times import Times
16
+ from ..types import BaseModel
17
+
18
+
19
+
20
+ _TIMERS = dict[str, 'TimerParams']
21
+ _WINDOWS = dict[str, 'WindowParams']
18
22
 
19
23
 
20
24
 
@@ -62,11 +66,24 @@ class TimersParams(BaseModel, extra='forbid'):
62
66
  Process and validate the core configuration parameters.
63
67
 
64
68
  :param timers: Seconds that are used for related timer.
65
- :param data: Keyword arguments passed to Pydantic model.
66
- Parameter is picked up by autodoc, please ignore.
67
69
  """
68
70
 
69
- timers: dict[str, TimerParams] = {}
71
+ timers: _TIMERS
72
+
73
+
74
+ def __init__(
75
+ self,
76
+ timers: Optional[_TIMERS] = None,
77
+ ) -> None:
78
+ """
79
+ Initialize instance for class using provided parameters.
80
+ """
81
+
82
+ if timers is None:
83
+ timers = {}
84
+
85
+ super().__init__(
86
+ timers=timers)
70
87
 
71
88
 
72
89
 
@@ -144,8 +161,21 @@ class WindowsParams(BaseModel, extra='forbid'):
144
161
  Process and validate the core configuration parameters.
145
162
 
146
163
  :param windows: Parameters for defining scheduled time.
147
- :param data: Keyword arguments passed to Pydantic model.
148
- Parameter is picked up by autodoc, please ignore.
149
164
  """
150
165
 
151
- windows: dict[str, WindowParams] = {}
166
+ windows: _WINDOWS
167
+
168
+
169
+ def __init__(
170
+ self,
171
+ windows: Optional[_WINDOWS] = None,
172
+ ) -> None:
173
+ """
174
+ Initialize instance for class using provided parameters.
175
+ """
176
+
177
+ if windows is None:
178
+ windows = {}
179
+
180
+ super().__init__(
181
+ windows=windows)
encommon/times/parse.py CHANGED
@@ -9,7 +9,6 @@ is permitted, for more information consult the project license file.
9
9
 
10
10
  from contextlib import suppress
11
11
  from datetime import datetime
12
- from datetime import timezone
13
12
  from re import match as re_match
14
13
  from typing import Optional
15
14
  from typing import TYPE_CHECKING
@@ -31,7 +30,7 @@ if TYPE_CHECKING:
31
30
 
32
31
 
33
32
 
34
- def parse_time( # noqa: CFQ004
33
+ def parse_time(
35
34
  source: Optional[PARSABLE] = None,
36
35
  *,
37
36
  anchor: Optional[PARSABLE] = None,
@@ -79,14 +78,20 @@ def parse_time( # noqa: CFQ004
79
78
  :returns: Python datetime object containing related time.
80
79
  """
81
80
 
81
+
82
82
  if (source is not None
83
83
  and hasattr(source, 'source')):
84
+
84
85
  source = source.source
86
+ assert isinstance(
87
+ source, datetime)
88
+
85
89
 
86
90
  if (isinstance(source, str)
87
91
  and re_match(NUMERISH, source)):
88
92
  source = float(source)
89
93
 
94
+
90
95
  tzinfo = findtz(tzname)
91
96
 
92
97
 
@@ -94,8 +99,11 @@ def parse_time( # noqa: CFQ004
94
99
  source = datetime.fromtimestamp(
95
100
  float(source), tz=tzinfo)
96
101
 
97
- if str(source) in STRINGNOW:
98
- return utcdatetime()
102
+
103
+ if source in STRINGNOW:
104
+ source = (
105
+ utcdatetime()
106
+ .astimezone(tzinfo))
99
107
 
100
108
  if source in ['max', float('inf')]:
101
109
  source = datetime.max
@@ -116,11 +124,15 @@ def parse_time( # noqa: CFQ004
116
124
  formats=format,
117
125
  tzname=tzname)
118
126
 
119
- if isinstance(source, datetime):
120
- return (
121
- source.replace(tzinfo=tzinfo)
122
- .astimezone(timezone.utc))
123
127
 
128
+ if (isinstance(source, datetime)
129
+ and not source.tzinfo):
130
+ source = source.replace(
131
+ tzinfo=findtz(tzname))
132
+
133
+
134
+ if isinstance(source, datetime):
135
+ return source
124
136
 
125
137
  raise ValueError('source') # NOCVR
126
138
 
@@ -155,7 +167,12 @@ def shift_time(
155
167
  anchor = parse_time(
156
168
  anchor, tzname=tzname)
157
169
 
158
- return snap(anchor, notate)
170
+ parsed = snap(anchor, notate)
171
+
172
+ assert parsed.tzinfo is not None
173
+
174
+ return parse_time(
175
+ parsed, tzname=tzname)
159
176
 
160
177
 
161
178
 
@@ -186,11 +203,21 @@ def string_time(
186
203
  """
187
204
 
188
205
  if formats is not None:
206
+
189
207
  with suppress(ValueError):
190
- return strptime(source, formats)
208
+
209
+ return strptime(
210
+ source, formats)
191
211
 
192
212
  parsed = parser.parse(source)
193
213
 
214
+ if parsed.tzinfo is None:
215
+
216
+ tzinfo = findtz(tzname)
217
+
218
+ parsed = parsed.replace(
219
+ tzinfo=tzinfo)
220
+
194
221
  return parse_time(
195
222
  parsed, tzname=tzname)
196
223
 
@@ -8,6 +8,7 @@ is permitted, for more information consult the project license file.
8
8
 
9
9
 
10
10
  from datetime import timedelta
11
+ from datetime import timezone
11
12
 
12
13
  from pytest import mark
13
14
 
@@ -41,10 +42,10 @@ def test_parse_time() -> None:
41
42
  '12/31/1969 6:00pm',
42
43
  tzname='US/Central')
43
44
 
44
- assert parsed.year == 1970
45
- assert parsed.month == 1
46
- assert parsed.day == 1
47
- assert parsed.hour == 0
45
+ assert parsed.year == 1969
46
+ assert parsed.month == 12
47
+ assert parsed.day == 31
48
+ assert parsed.hour == 18
48
49
 
49
50
 
50
51
  parsed = parse_time(0)
@@ -139,7 +140,10 @@ def test_string_time() -> None:
139
140
  Perform various tests associated with relevant routines.
140
141
  """
141
142
 
142
- expect = utcdatetime(1980, 1, 1)
143
+ utc = timezone.utc
144
+ expect = (
145
+ utcdatetime(1980, 1, 1)
146
+ .astimezone(None))
143
147
 
144
148
 
145
149
  strings = [
@@ -151,7 +155,9 @@ def test_string_time() -> None:
151
155
 
152
156
  for string in strings:
153
157
 
154
- parsed = string_time(string)
158
+ parsed = (
159
+ string_time(string)
160
+ .astimezone(utc))
155
161
 
156
162
  assert parsed == expect
157
163
 
@@ -170,9 +176,10 @@ def test_string_time() -> None:
170
176
  assert parsed == expect
171
177
 
172
178
 
173
- parsed = string_time(
174
- '1979-12-31 18:00:00',
175
- tzname='US/Central')
179
+ parsed = (
180
+ string_time(
181
+ '1979-12-31 18:00:00',
182
+ tzname='US/Central'))
176
183
 
177
184
  assert parsed == expect
178
185
 
@@ -30,8 +30,7 @@ def test_Times() -> None:
30
30
  attrs = list(times.__dict__)
31
31
 
32
32
  assert attrs == [
33
- '_Times__source',
34
- '_Times__hashed']
33
+ '_Times__source']
35
34
 
36
35
 
37
36
  assert inrepr(
@@ -65,8 +64,12 @@ def test_Times() -> None:
65
64
 
66
65
  assert times.epoch == 0.0
67
66
 
67
+ assert times.spoch == 0
68
+
68
69
  assert times.mpoch == 0.0
69
70
 
71
+ assert str(times.time) == '00:00:00'
72
+
70
73
  assert times.simple == UNIXEPOCH
71
74
 
72
75
  assert times.subsec == UNIXMPOCH
@@ -87,3 +90,33 @@ def test_Times() -> None:
87
90
 
88
91
  times = times.shift('+1y')
89
92
  assert times == '1971-01-01'
93
+
94
+ times = times.shifz('UTC-1')
95
+ assert times == (
96
+ '12/31/1970 23:00 -0100')
97
+
98
+
99
+
100
+ def test_Times_tzname() -> None:
101
+ """
102
+ Perform various tests associated with relevant routines.
103
+ """
104
+
105
+ times1 = Times(
106
+ '1970-01-01T00:00:00Z')
107
+
108
+ times2 = times1.shifz(
109
+ 'US/Central')
110
+
111
+
112
+ delta = times1 - times2
113
+
114
+ assert -1 < delta < 1
115
+
116
+
117
+ stamp1 = times1.stamp(
118
+ tzname='US/Central')
119
+
120
+ stamp2 = times2.stamp()
121
+
122
+ assert stamp1 == stamp2
@@ -0,0 +1,23 @@
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 ..unitime import unitime
11
+
12
+
13
+
14
+ def test_unitime() -> None:
15
+ """
16
+ Perform various tests associated with relevant routines.
17
+ """
18
+
19
+ assert unitime('1s') == 1
20
+ assert unitime('1h') == 3600
21
+ assert unitime('1') == 1
22
+ assert unitime(1) == 1
23
+ assert unitime('1.0') == 1
encommon/times/timers.py CHANGED
@@ -430,12 +430,18 @@ class Timers:
430
430
  :param unique: Unique identifier for the related child.
431
431
  """
432
432
 
433
+ params = self.__params
433
434
  timers = self.__timers
434
435
 
435
436
  group = self.__group
436
437
 
437
438
  session = self.store_session
438
439
 
440
+ config = params.timers
441
+
442
+
443
+ if unique in config:
444
+ del config[unique]
439
445
 
440
446
  if unique in timers:
441
447
  del timers[unique]
encommon/times/times.py CHANGED
@@ -9,6 +9,7 @@ is permitted, for more information consult the project license file.
9
9
 
10
10
  from contextlib import suppress
11
11
  from datetime import datetime
12
+ from datetime import time as dtime
12
13
  from datetime import timedelta
13
14
  from typing import Optional
14
15
 
@@ -40,7 +41,6 @@ class Times:
40
41
  """
41
42
 
42
43
  __source: datetime
43
- __hashed: int
44
44
 
45
45
 
46
46
  def __init__(
@@ -62,8 +62,6 @@ class Times:
62
62
  tzname=tzname)
63
63
 
64
64
  self.__source = parsed
65
- self.__hashed = int(
66
- self.mpoch * 1000)
67
65
 
68
66
 
69
67
  def __repr__(
@@ -87,7 +85,9 @@ class Times:
87
85
  :returns: Boolean indicating outcome from the operation.
88
86
  """
89
87
 
90
- return int(1e9 + self.__hashed)
88
+ hashed = int(self.mpoch)
89
+
90
+ return int(1e9 + hashed)
91
91
 
92
92
 
93
93
  def __str__(
@@ -291,6 +291,19 @@ class Times:
291
291
  return source.timestamp()
292
292
 
293
293
 
294
+ @property
295
+ def spoch(
296
+ self,
297
+ ) -> int:
298
+ """
299
+ Return the seconds since the Unix epoch for the instance.
300
+
301
+ :returns: Seconds since the Unix epoch for the instance.
302
+ """
303
+
304
+ return int(self.epoch)
305
+
306
+
294
307
  @property
295
308
  def mpoch(
296
309
  self,
@@ -304,14 +317,27 @@ class Times:
304
317
  return self.epoch * 1000
305
318
 
306
319
 
320
+ @property
321
+ def time(
322
+ self,
323
+ ) -> dtime:
324
+ """
325
+ Return the value for the attribute from class instance.
326
+
327
+ :returns: Value for the attribute from class instance.
328
+ """
329
+
330
+ return self.__source.time()
331
+
332
+
307
333
  @property
308
334
  def simple(
309
335
  self,
310
336
  ) -> str:
311
337
  """
312
- Return the timestamp using provided format for instance.
338
+ Return the value for the attribute from class instance.
313
339
 
314
- :returns: Timestamp using provided format for instance.
340
+ :returns: Value for the attribute from class instance.
315
341
  """
316
342
 
317
343
  return self.stamp(STAMP_SIMPLE)
@@ -322,9 +348,9 @@ class Times:
322
348
  self,
323
349
  ) -> str:
324
350
  """
325
- Return the timestamp using provided format for instance.
351
+ Return the value for the attribute from class instance.
326
352
 
327
- :returns: Timestamp using provided format for instance.
353
+ :returns: Value for the attribute from class instance.
328
354
  """
329
355
 
330
356
  return self.stamp(STAMP_SUBSEC)
@@ -335,9 +361,9 @@ class Times:
335
361
  self,
336
362
  ) -> str:
337
363
  """
338
- Return the timestamp using provided format for instance.
364
+ Return the value for the attribute from class instance.
339
365
 
340
- :returns: Timestamp using provided format for instance.
366
+ :returns: Value for the attribute from class instance.
341
367
  """
342
368
 
343
369
  return self.stamp(STAMP_HUMAN)
@@ -423,9 +449,14 @@ class Times:
423
449
 
424
450
  tzinfo = findtz(tzname)
425
451
 
426
- parsed = source.astimezone(tzinfo)
452
+ if tzname is not None:
453
+
454
+ source = (
455
+ source
456
+ .astimezone(tzinfo))
427
457
 
428
- return strftime(parsed, format)
458
+ return strftime(
459
+ source, format)
429
460
 
430
461
 
431
462
  def shift(
@@ -441,4 +472,31 @@ class Times:
441
472
 
442
473
  source = self.__source
443
474
 
444
- return Times(notate, anchor=source)
475
+ return Times(
476
+ notate, anchor=source)
477
+
478
+
479
+ def shifz(
480
+ self,
481
+ tzname: str,
482
+ ) -> 'Times':
483
+ """
484
+ Return the new instance of object shifted using datetime.
485
+
486
+ :param tzname: Name of the timezone associated to source.
487
+ This is not relevant in timezone included in source.
488
+ :returns: New instance of the class using shifted time.
489
+ """
490
+
491
+ source = self.__source
492
+
493
+ tzinfo = findtz(tzname)
494
+
495
+ if tzname is not None:
496
+
497
+ source = (
498
+ source
499
+ .astimezone(tzinfo))
500
+
501
+ return Times(
502
+ source, tzname=tzname)
@@ -0,0 +1,48 @@
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 match as re_match
11
+
12
+ from .parse import since_time
13
+
14
+
15
+
16
+ def unitime(
17
+ input: int | float | str,
18
+ ) -> int:
19
+ """
20
+ Return the seconds in integer format for provided input.
21
+
22
+ :param input: Input that will be converted into seconds.
23
+ :returns: Seconds in integer format for provided input.
24
+ """
25
+
26
+ notate = r'^(\d+(s|m|h|d|w|y))*$'
27
+ strint = r'^\d+$'
28
+ strflt = r'^\d+\.\d+$'
29
+
30
+ if isinstance(input, str):
31
+
32
+ if re_match(notate, input):
33
+ input = since_time(
34
+ 'now', f'+{input}')
35
+
36
+ elif re_match(strint, input):
37
+ input = int(input)
38
+
39
+ elif re_match(strflt, input):
40
+ input = int(
41
+ input.split('.')[0])
42
+
43
+ if isinstance(input, float):
44
+ input = int(input)
45
+
46
+ assert isinstance(input, int)
47
+
48
+ return input
encommon/times/windows.py CHANGED
@@ -495,12 +495,18 @@ class Windows:
495
495
  :param unique: Unique identifier for the related child.
496
496
  """
497
497
 
498
+ params = self.__params
498
499
  windows = self.__windows
499
500
 
500
501
  group = self.__group
501
502
 
502
503
  session = self.store_session
503
504
 
505
+ config = params.windows
506
+
507
+
508
+ if unique in config:
509
+ del config[unique]
504
510
 
505
511
  if unique in windows:
506
512
  del windows[unique]
@@ -7,27 +7,45 @@ is permitted, for more information consult the project license file.
7
7
 
8
8
 
9
9
 
10
+ from .classes import BaseModel
11
+ from .classes import clsname
12
+ from .classes import lattrs
10
13
  from .dicts import merge_dicts
11
14
  from .dicts import sort_dict
12
15
  from .empty import Empty
16
+ from .lists import inlist
13
17
  from .notate import delate
14
18
  from .notate import getate
15
19
  from .notate import setate
16
20
  from .strings import hasstr
17
21
  from .strings import inrepr
18
22
  from .strings import instr
19
- from .strings import striplower
23
+ from .strings import rplstr
24
+ from .strings import strplwr
25
+ from .types import DictStrAny
26
+ from .types import NCFalse
27
+ from .types import NCNone
28
+ from .types import NCTrue
20
29
 
21
30
 
22
31
 
23
32
  __all__ = [
33
+ 'BaseModel',
34
+ 'clsname',
24
35
  'delate',
36
+ 'DictStrAny',
25
37
  'Empty',
26
38
  'getate',
27
39
  'hasstr',
40
+ 'inlist',
28
41
  'inrepr',
29
42
  'instr',
43
+ 'lattrs',
30
44
  'merge_dicts',
45
+ 'rplstr',
31
46
  'setate',
32
47
  'sort_dict',
33
- 'striplower']
48
+ 'strplwr',
49
+ 'NCTrue',
50
+ 'NCFalse',
51
+ 'NCNone']
@@ -0,0 +1,97 @@
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 typing import Any
11
+
12
+ from pydantic import BaseModel as Pydantic
13
+
14
+ from .types import DictStrAny
15
+
16
+
17
+
18
+ class BaseModel(Pydantic, extra='forbid'):
19
+ """
20
+ Pydantic base model but with added methods and routines.
21
+
22
+ :param data: Keyword arguments passed to Pydantic model.
23
+ """
24
+
25
+
26
+ def __init__(
27
+ self,
28
+ **data: Any,
29
+ ) -> None:
30
+ """
31
+ Initialize instance for class using provided parameters.
32
+ """
33
+
34
+ super().__init__(**data)
35
+
36
+
37
+ @property
38
+ def model_dumped(
39
+ self,
40
+ ) -> DictStrAny:
41
+ """
42
+ Return the facts about the attributes from the instance.
43
+
44
+ :returns: Facts about the attributes from the instance.
45
+ """
46
+
47
+ return self.model_dump()
48
+
49
+
50
+ @property
51
+ def model_pruned(
52
+ self,
53
+ ) -> DictStrAny:
54
+ """
55
+ Return the facts about the attributes from the instance.
56
+
57
+ :returns: Facts about the attributes from the instance.
58
+ """
59
+
60
+ return self.model_dump(
61
+ exclude_none=True)
62
+
63
+
64
+
65
+ def clsname(
66
+ cls: object,
67
+ ) -> str:
68
+ """
69
+ Return the actual definition name for the Python class.
70
+
71
+ :param cls: Provided Python class related to operation.
72
+ :returns: Actual definition name for the Python class.
73
+ """
74
+
75
+ assert hasattr(
76
+ cls, '__class__')
77
+
78
+ _cls = cls.__class__
79
+
80
+ assert hasattr(
81
+ _cls, '__name__')
82
+
83
+ return str(_cls.__name__)
84
+
85
+
86
+
87
+ def lattrs(
88
+ cls: object,
89
+ ) -> list[str]:
90
+ """
91
+ Return the list of attributes which are found in class.
92
+
93
+ :param cls: Provided Python class related to operation.
94
+ :returns: List of attributes which are found in class.
95
+ """
96
+
97
+ return list(cls.__dict__)