encommon 0.5.0__tar.gz → 0.7.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.
Files changed (73) hide show
  1. {encommon-0.5.0/encommon.egg-info → encommon-0.7.0}/PKG-INFO +1 -1
  2. {encommon-0.5.0 → encommon-0.7.0}/encommon/config/config.py +2 -2
  3. {encommon-0.5.0 → encommon-0.7.0}/encommon/conftest.py +2 -1
  4. {encommon-0.5.0 → encommon-0.7.0}/encommon/times/test/test_timers.py +46 -3
  5. encommon-0.7.0/encommon/times/timers.py +287 -0
  6. {encommon-0.5.0 → encommon-0.7.0}/encommon/utils/__init__.py +2 -0
  7. encommon-0.7.0/encommon/utils/stdout.py +335 -0
  8. encommon-0.7.0/encommon/utils/test/test_stdout.py +231 -0
  9. encommon-0.7.0/encommon/version.txt +1 -0
  10. {encommon-0.5.0 → encommon-0.7.0/encommon.egg-info}/PKG-INFO +1 -1
  11. {encommon-0.5.0 → encommon-0.7.0}/setup.cfg +3 -0
  12. encommon-0.5.0/encommon/times/timers.py +0 -144
  13. encommon-0.5.0/encommon/utils/stdout.py +0 -123
  14. encommon-0.5.0/encommon/utils/test/test_stdout.py +0 -80
  15. encommon-0.5.0/encommon/version.txt +0 -1
  16. {encommon-0.5.0 → encommon-0.7.0}/LICENSE +0 -0
  17. {encommon-0.5.0 → encommon-0.7.0}/MANIFEST.in +0 -0
  18. {encommon-0.5.0 → encommon-0.7.0}/README.md +0 -0
  19. {encommon-0.5.0 → encommon-0.7.0}/encommon/__init__.py +0 -0
  20. {encommon-0.5.0 → encommon-0.7.0}/encommon/config/__init__.py +0 -0
  21. {encommon-0.5.0 → encommon-0.7.0}/encommon/config/common.py +0 -0
  22. {encommon-0.5.0 → encommon-0.7.0}/encommon/config/files.py +0 -0
  23. {encommon-0.5.0 → encommon-0.7.0}/encommon/config/logger.py +0 -0
  24. {encommon-0.5.0 → encommon-0.7.0}/encommon/config/params.py +0 -0
  25. {encommon-0.5.0 → encommon-0.7.0}/encommon/config/paths.py +0 -0
  26. {encommon-0.5.0 → encommon-0.7.0}/encommon/config/test/__init__.py +0 -0
  27. {encommon-0.5.0 → encommon-0.7.0}/encommon/config/test/test_common.py +0 -0
  28. {encommon-0.5.0 → encommon-0.7.0}/encommon/config/test/test_config.py +0 -0
  29. {encommon-0.5.0 → encommon-0.7.0}/encommon/config/test/test_files.py +0 -0
  30. {encommon-0.5.0 → encommon-0.7.0}/encommon/config/test/test_logger.py +0 -0
  31. {encommon-0.5.0 → encommon-0.7.0}/encommon/config/test/test_paths.py +0 -0
  32. {encommon-0.5.0 → encommon-0.7.0}/encommon/crypts/__init__.py +0 -0
  33. {encommon-0.5.0 → encommon-0.7.0}/encommon/crypts/crypts.py +0 -0
  34. {encommon-0.5.0 → encommon-0.7.0}/encommon/crypts/hashes.py +0 -0
  35. {encommon-0.5.0 → encommon-0.7.0}/encommon/crypts/params.py +0 -0
  36. {encommon-0.5.0 → encommon-0.7.0}/encommon/crypts/test/__init__.py +0 -0
  37. {encommon-0.5.0 → encommon-0.7.0}/encommon/crypts/test/test_crypts.py +0 -0
  38. {encommon-0.5.0 → encommon-0.7.0}/encommon/crypts/test/test_hashes.py +0 -0
  39. {encommon-0.5.0 → encommon-0.7.0}/encommon/py.typed +0 -0
  40. {encommon-0.5.0 → encommon-0.7.0}/encommon/times/__init__.py +0 -0
  41. {encommon-0.5.0 → encommon-0.7.0}/encommon/times/common.py +0 -0
  42. {encommon-0.5.0 → encommon-0.7.0}/encommon/times/duration.py +0 -0
  43. {encommon-0.5.0 → encommon-0.7.0}/encommon/times/parse.py +0 -0
  44. {encommon-0.5.0 → encommon-0.7.0}/encommon/times/test/__init__.py +0 -0
  45. {encommon-0.5.0 → encommon-0.7.0}/encommon/times/test/test_common.py +0 -0
  46. {encommon-0.5.0 → encommon-0.7.0}/encommon/times/test/test_duration.py +0 -0
  47. {encommon-0.5.0 → encommon-0.7.0}/encommon/times/test/test_parse.py +0 -0
  48. {encommon-0.5.0 → encommon-0.7.0}/encommon/times/test/test_times.py +0 -0
  49. {encommon-0.5.0 → encommon-0.7.0}/encommon/times/test/test_window.py +0 -0
  50. {encommon-0.5.0 → encommon-0.7.0}/encommon/times/times.py +0 -0
  51. {encommon-0.5.0 → encommon-0.7.0}/encommon/times/window.py +0 -0
  52. {encommon-0.5.0 → encommon-0.7.0}/encommon/types/__init__.py +0 -0
  53. {encommon-0.5.0 → encommon-0.7.0}/encommon/types/dicts.py +0 -0
  54. {encommon-0.5.0 → encommon-0.7.0}/encommon/types/empty.py +0 -0
  55. {encommon-0.5.0 → encommon-0.7.0}/encommon/types/strings.py +0 -0
  56. {encommon-0.5.0 → encommon-0.7.0}/encommon/types/test/__init__.py +0 -0
  57. {encommon-0.5.0 → encommon-0.7.0}/encommon/types/test/test_dicts.py +0 -0
  58. {encommon-0.5.0 → encommon-0.7.0}/encommon/types/test/test_empty.py +0 -0
  59. {encommon-0.5.0 → encommon-0.7.0}/encommon/types/test/test_strings.py +0 -0
  60. {encommon-0.5.0 → encommon-0.7.0}/encommon/utils/common.py +0 -0
  61. {encommon-0.5.0 → encommon-0.7.0}/encommon/utils/match.py +0 -0
  62. {encommon-0.5.0 → encommon-0.7.0}/encommon/utils/paths.py +0 -0
  63. {encommon-0.5.0 → encommon-0.7.0}/encommon/utils/sample.py +0 -0
  64. {encommon-0.5.0 → encommon-0.7.0}/encommon/utils/test/__init__.py +0 -0
  65. {encommon-0.5.0 → encommon-0.7.0}/encommon/utils/test/test_match.py +0 -0
  66. {encommon-0.5.0 → encommon-0.7.0}/encommon/utils/test/test_paths.py +0 -0
  67. {encommon-0.5.0 → encommon-0.7.0}/encommon/utils/test/test_sample.py +0 -0
  68. {encommon-0.5.0 → encommon-0.7.0}/encommon.egg-info/SOURCES.txt +0 -0
  69. {encommon-0.5.0 → encommon-0.7.0}/encommon.egg-info/dependency_links.txt +0 -0
  70. {encommon-0.5.0 → encommon-0.7.0}/encommon.egg-info/requires.txt +0 -0
  71. {encommon-0.5.0 → encommon-0.7.0}/encommon.egg-info/top_level.txt +0 -0
  72. {encommon-0.5.0 → encommon-0.7.0}/pyproject.toml +0 -0
  73. {encommon-0.5.0 → encommon-0.7.0}/reqs-install.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: encommon
3
- Version: 0.5.0
3
+ Version: 0.7.0
4
4
  Summary: Enasis Network Common Library
5
5
  License: MIT
6
6
  Classifier: Programming Language :: Python :: 3
@@ -155,9 +155,9 @@ class Config:
155
155
  self,
156
156
  ) -> Params:
157
157
  """
158
- Return the configuration in the object format for files.
158
+ Return the Pydantic model containing the configuration.
159
159
 
160
- :returns: Configuration in the object format for files.
160
+ :returns: Pydantic model containing the configuration.
161
161
  """
162
162
 
163
163
  if self.__params is not None:
@@ -21,6 +21,7 @@ def config_path(
21
21
  Construct the directory and files needed for the tests.
22
22
 
23
23
  :param tmp_path: pytest object for temporal filesystem.
24
+ :returns: New resolved filesystem path object instance.
24
25
  """
25
26
 
26
27
 
@@ -40,4 +41,4 @@ def config_path(
40
41
  .write_text('name: Tony Stark'))
41
42
 
42
43
 
43
- return tmp_path
44
+ return tmp_path.resolve()
@@ -7,6 +7,7 @@ is permitted, for more information consult the project license file.
7
7
 
8
8
 
9
9
 
10
+ from pathlib import Path
10
11
  from time import sleep
11
12
 
12
13
  from pytest import raises
@@ -25,8 +26,10 @@ def test_Timers() -> None:
25
26
  attrs = list(timers.__dict__)
26
27
 
27
28
  assert attrs == [
28
- '_Timers__timing',
29
- '_Timers__caches']
29
+ '_Timers__timers',
30
+ '_Timers__cache_file',
31
+ '_Timers__cache_name',
32
+ '_Timers__cache_dict']
30
33
 
31
34
 
32
35
  assert repr(timers).startswith(
@@ -36,7 +39,11 @@ def test_Timers() -> None:
36
39
  '<encommon.times.timers.Timers')
37
40
 
38
41
 
39
- assert timers.timing == {'one': 1}
42
+ assert timers.timers == {'one': 1}
43
+ assert timers.cache_file is not None
44
+ assert len(timers.cache_dict) == 1
45
+ assert timers.cache_name is not None
46
+
40
47
 
41
48
  assert not timers.ready('one')
42
49
  sleep(1.1)
@@ -50,6 +57,42 @@ def test_Timers() -> None:
50
57
 
51
58
 
52
59
 
60
+ def test_Timers_cache(
61
+ tmp_path: Path,
62
+ ) -> None:
63
+ """
64
+ Perform various tests associated with relevant routines.
65
+
66
+ :param tmp_path: pytest object for temporal filesystem.
67
+ """
68
+
69
+ cache_file = (
70
+ f'{tmp_path}/timers.db')
71
+
72
+ timers1 = Timers(
73
+ timers={'one': 1},
74
+ cache_file=cache_file)
75
+
76
+ assert not timers1.ready('one')
77
+
78
+ sleep(0.75)
79
+
80
+ timers2 = Timers(
81
+ timers={'one': 1},
82
+ cache_file=cache_file)
83
+
84
+ assert not timers1.ready('one')
85
+ assert not timers2.ready('one')
86
+
87
+ sleep(0.25)
88
+
89
+ timers2.load_cache()
90
+
91
+ assert timers1.ready('one')
92
+ assert timers2.ready('one')
93
+
94
+
95
+
53
96
  def test_Timers_raises() -> None:
54
97
  """
55
98
  Perform various tests associated with relevant routines.
@@ -0,0 +1,287 @@
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 sqlite3 import connect as SQLite
11
+ from typing import Optional
12
+ from typing import TYPE_CHECKING
13
+
14
+ from .common import NUMERIC
15
+ from .common import PARSABLE
16
+ from .times import Times
17
+
18
+ if TYPE_CHECKING:
19
+ from sqlite3 import Connection
20
+
21
+
22
+ TABLE = (
23
+ """
24
+ create table
25
+ if not exists
26
+ {0} (
27
+ "unique" text not null,
28
+ "update" text not null,
29
+ primary key ("unique"));
30
+ """) # noqa: LIT003
31
+
32
+
33
+
34
+ class Timers:
35
+ """
36
+ Track timers on unique key and determine when to proceed.
37
+
38
+ .. warning::
39
+ This class will use an in-memory database for cache,
40
+ unless a cache file is explicity defined.
41
+
42
+ .. testsetup::
43
+ >>> from time import sleep
44
+
45
+ Example
46
+ -------
47
+ >>> timers = Timers({'one': 1})
48
+ >>> timers.ready('one')
49
+ False
50
+ >>> sleep(1)
51
+ >>> timers.ready('one')
52
+ True
53
+
54
+ :param timers: Seconds that are used for each of timers.
55
+ :param cache_file: Optional path to SQLite database for
56
+ cache. This will allow for use between executions.
57
+ :param cache_name: Optional override default table name.
58
+ """
59
+
60
+ __timers: dict[str, float]
61
+ __cache_file: 'Connection'
62
+ __cache_name: str
63
+ __cache_dict: dict[str, Times]
64
+
65
+
66
+ def __init__(
67
+ self,
68
+ timers: Optional[dict[str, NUMERIC]] = None,
69
+ cache_file: str = ':memory:',
70
+ cache_name: str = 'encommon_timers',
71
+ ) -> None:
72
+ """
73
+ Initialize instance for class using provided parameters.
74
+ """
75
+
76
+ timers = timers or {}
77
+
78
+
79
+ self.__timers = {
80
+ k: float(v)
81
+ for k, v in
82
+ timers.items()}
83
+
84
+
85
+ cached = SQLite(cache_file)
86
+
87
+ cached.execute(
88
+ TABLE.format(cache_name))
89
+
90
+ cached.commit()
91
+
92
+ self.__cache_file = cached
93
+ self.__cache_name = cache_name
94
+
95
+
96
+ self.__cache_dict = {
97
+ x: Times()
98
+ for x in
99
+ self.__timers}
100
+
101
+
102
+ self.load_cache()
103
+ self.save_cache()
104
+
105
+
106
+ def load_cache(
107
+ self,
108
+ ) -> None:
109
+ """
110
+ Load the timers cache from the database into attribute.
111
+ """
112
+
113
+ cached = self.__cache_file
114
+ table = self.__cache_name
115
+ cachem = self.__cache_dict
116
+
117
+ cursor = cached.execute(
118
+ f'select * from {table}'
119
+ ' order by "unique" asc')
120
+
121
+ records = cursor.fetchall()
122
+
123
+ for record in records:
124
+
125
+ unique = record[0]
126
+ update = record[1]
127
+
128
+ times = Times(update)
129
+
130
+ cachem[unique] = times
131
+
132
+
133
+ def save_cache(
134
+ self,
135
+ ) -> None:
136
+ """
137
+ Save the timers cache from the attribute into database.
138
+ """
139
+
140
+ cached = self.__cache_file
141
+ table = self.__cache_name
142
+ cachem = self.__cache_dict
143
+
144
+ insert = [
145
+ (k, str(v)) for k, v
146
+ in cachem.items()]
147
+
148
+ cached.executemany(
149
+ (f'replace into {table}'
150
+ ' ("unique", "update")'
151
+ ' values (?, ?)'),
152
+ tuple(insert))
153
+
154
+ cached.commit()
155
+
156
+
157
+ @property
158
+ def timers(
159
+ self,
160
+ ) -> dict[str, float]:
161
+ """
162
+ Return the property for attribute from the class instance.
163
+
164
+ :returns: Property for attribute from the class instance.
165
+ """
166
+
167
+ return dict(self.__timers)
168
+
169
+
170
+ @property
171
+ def cache_file(
172
+ self,
173
+ ) -> 'Connection':
174
+ """
175
+ Return the property for attribute from the class instance.
176
+
177
+ :returns: Property for attribute from the class instance.
178
+ """
179
+
180
+ return self.__cache_file
181
+
182
+
183
+ @property
184
+ def cache_dict(
185
+ self,
186
+ ) -> dict[str, Times]:
187
+ """
188
+ Return the property for attribute from the class instance.
189
+
190
+ :returns: Property for attribute from the class instance.
191
+ """
192
+
193
+ return dict(self.__cache_dict)
194
+
195
+
196
+ @property
197
+ def cache_name(
198
+ self,
199
+ ) -> str:
200
+ """
201
+ Return the property for attribute from the class instance.
202
+
203
+ :returns: Property for attribute from the class instance.
204
+ """
205
+
206
+ return self.__cache_name
207
+
208
+
209
+ def ready(
210
+ self,
211
+ unique: str,
212
+ update: bool = True,
213
+ ) -> bool:
214
+ """
215
+ Determine whether or not the appropriate time has passed.
216
+
217
+ .. note::
218
+ For performance reasons, this method will not notice
219
+ changes within the database unless refreshed first.
220
+
221
+ :param unique: Unique identifier for the timer in mapping.
222
+ :param update: Determines whether or not time is updated.
223
+ """
224
+
225
+ timers = self.__timers
226
+ caches = self.__cache_dict
227
+
228
+ if unique not in caches:
229
+ raise ValueError('unique')
230
+
231
+ cache = caches[unique]
232
+ timer = timers[unique]
233
+
234
+ ready = cache.elapsed >= timer
235
+
236
+ if ready and update:
237
+ self.update(unique)
238
+
239
+ return ready
240
+
241
+
242
+ def update(
243
+ self,
244
+ unique: str,
245
+ started: Optional[PARSABLE] = None,
246
+ ) -> None:
247
+ """
248
+ Update the existing timer from mapping within the cache.
249
+
250
+ :param unique: Unique identifier for the timer in mapping.
251
+ :param started: Override the start time for timer value.
252
+ """
253
+
254
+ caches = self.__cache_dict
255
+
256
+ if unique not in caches:
257
+ raise ValueError('unique')
258
+
259
+ caches[unique] = Times(started)
260
+
261
+ self.save_cache()
262
+
263
+
264
+ def create(
265
+ self,
266
+ unique: str,
267
+ minimum: int | float,
268
+ started: Optional[PARSABLE] = None,
269
+ ) -> None:
270
+ """
271
+ Update the existing timer from mapping within the cache.
272
+
273
+ :param unique: Unique identifier for the timer in mapping.
274
+ :param minimum: Determines minimum seconds that must pass.
275
+ :param started: Determines when the time starts for timer.
276
+ """
277
+
278
+ timers = self.__timers
279
+ caches = self.__cache_dict
280
+
281
+ if unique in caches:
282
+ raise ValueError('unique')
283
+
284
+ timers[unique] = float(minimum)
285
+ caches[unique] = Times(started)
286
+
287
+ self.save_cache()
@@ -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',