encommon 0.10.0__py3-none-any.whl → 0.11.1__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 +19 -7
- encommon/config/files.py +3 -3
- encommon/config/logger.py +39 -7
- encommon/config/params.py +21 -1
- encommon/config/paths.py +2 -2
- encommon/config/test/test_logger.py +4 -1
- encommon/config/test/{test_common.py → test_utils.py} +3 -3
- encommon/config/{common.py → utils.py} +1 -10
- encommon/conftest.py +2 -1
- encommon/crypts/crypts.py +68 -18
- encommon/crypts/params.py +14 -1
- encommon/crypts/test/test_crypts.py +56 -13
- 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 +81 -41
- 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 +250 -0
- encommon/times/timer.py +147 -0
- encommon/times/timers.py +217 -130
- encommon/times/times.py +6 -6
- encommon/times/utils.py +148 -0
- encommon/times/window.py +124 -85
- encommon/times/windows.py +472 -0
- encommon/types/notate.py +0 -2
- 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.10.0.dist-info → encommon-0.11.1.dist-info}/METADATA +1 -1
- encommon-0.11.1.dist-info/RECORD +73 -0
- encommon-0.10.0.dist-info/RECORD +0 -65
- {encommon-0.10.0.dist-info → encommon-0.11.1.dist-info}/LICENSE +0 -0
- {encommon-0.10.0.dist-info → encommon-0.11.1.dist-info}/WHEEL +0 -0
- {encommon-0.10.0.dist-info → encommon-0.11.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,472 @@
|
|
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
|
+
from sqlite3 import Connection
|
12
|
+
from sqlite3 import connect as SQLite
|
13
|
+
from typing import Optional
|
14
|
+
from typing import TYPE_CHECKING
|
15
|
+
|
16
|
+
from .common import PARSABLE
|
17
|
+
from .times import Times
|
18
|
+
from .window import Window
|
19
|
+
|
20
|
+
if TYPE_CHECKING:
|
21
|
+
from .params import WindowParams
|
22
|
+
from .params import WindowsParams
|
23
|
+
|
24
|
+
|
25
|
+
|
26
|
+
CACHE_TABLE = (
|
27
|
+
"""
|
28
|
+
create table if not exists
|
29
|
+
{0} (
|
30
|
+
"group" text not null,
|
31
|
+
"unique" text not null,
|
32
|
+
"last" text not null,
|
33
|
+
"next" text not null,
|
34
|
+
"update" text not null,
|
35
|
+
primary key (
|
36
|
+
"group", "unique"));
|
37
|
+
""") # noqa: LIT003
|
38
|
+
|
39
|
+
|
40
|
+
|
41
|
+
WINDOWS = dict[str, Window]
|
42
|
+
|
43
|
+
|
44
|
+
|
45
|
+
class Windows:
|
46
|
+
"""
|
47
|
+
Track windows on unique key determining when to proceed.
|
48
|
+
|
49
|
+
.. warning::
|
50
|
+
This class will use an in-memory database for cache,
|
51
|
+
unless a cache file is explicity defined.
|
52
|
+
|
53
|
+
.. testsetup::
|
54
|
+
>>> from .params import WindowParams
|
55
|
+
>>> from .params import WindowsParams
|
56
|
+
|
57
|
+
Example
|
58
|
+
-------
|
59
|
+
>>> source = {'one': WindowParams(window=1)}
|
60
|
+
>>> params = WindowsParams(windows=source)
|
61
|
+
>>> windows = Windows(params, '-2s', 'now')
|
62
|
+
>>> [windows.ready('one') for x in range(3)]
|
63
|
+
[True, True, False]
|
64
|
+
|
65
|
+
:param params: Parameters for instantiating the instance.
|
66
|
+
:param start: Determine the start for scheduling window.
|
67
|
+
:param stop: Determine the ending for scheduling window.
|
68
|
+
:param file: Optional path to file for SQLite database,
|
69
|
+
allowing for state retention between the executions.
|
70
|
+
:param table: Optional override for default table name.
|
71
|
+
:param group: Optional override for default group name.
|
72
|
+
"""
|
73
|
+
|
74
|
+
__params: 'WindowsParams'
|
75
|
+
|
76
|
+
__start: Times
|
77
|
+
__stop: Times
|
78
|
+
|
79
|
+
__sqlite: Connection
|
80
|
+
__file: str
|
81
|
+
__table: str
|
82
|
+
__group: str
|
83
|
+
|
84
|
+
__windows: WINDOWS
|
85
|
+
|
86
|
+
|
87
|
+
def __init__( # noqa: CFQ002
|
88
|
+
self,
|
89
|
+
params: Optional['WindowsParams'] = None,
|
90
|
+
start: PARSABLE = 'now',
|
91
|
+
stop: PARSABLE = '3000-01-01',
|
92
|
+
*,
|
93
|
+
file: str = ':memory:',
|
94
|
+
table: str = 'windows',
|
95
|
+
group: str = 'default',
|
96
|
+
) -> None:
|
97
|
+
"""
|
98
|
+
Initialize instance for class using provided parameters.
|
99
|
+
"""
|
100
|
+
|
101
|
+
from .params import WindowsParams
|
102
|
+
|
103
|
+
if params is None:
|
104
|
+
params = WindowsParams()
|
105
|
+
|
106
|
+
self.__params = deepcopy(params)
|
107
|
+
|
108
|
+
|
109
|
+
start = Times(start)
|
110
|
+
stop = Times(stop)
|
111
|
+
|
112
|
+
assert stop > start
|
113
|
+
|
114
|
+
self.__start = start
|
115
|
+
self.__stop = stop
|
116
|
+
|
117
|
+
|
118
|
+
sqlite = SQLite(file)
|
119
|
+
|
120
|
+
sqlite.execute(
|
121
|
+
CACHE_TABLE
|
122
|
+
.format(table))
|
123
|
+
|
124
|
+
sqlite.commit()
|
125
|
+
|
126
|
+
self.__sqlite = sqlite
|
127
|
+
self.__file = file
|
128
|
+
self.__table = table
|
129
|
+
self.__group = group
|
130
|
+
|
131
|
+
|
132
|
+
self.__windows = {}
|
133
|
+
|
134
|
+
self.load_children()
|
135
|
+
|
136
|
+
|
137
|
+
@property
|
138
|
+
def params(
|
139
|
+
self,
|
140
|
+
) -> 'WindowsParams':
|
141
|
+
"""
|
142
|
+
Return the Pydantic model containing the configuration.
|
143
|
+
|
144
|
+
:returns: Pydantic model containing the configuration.
|
145
|
+
"""
|
146
|
+
|
147
|
+
return self.__params
|
148
|
+
|
149
|
+
|
150
|
+
@property
|
151
|
+
def start(
|
152
|
+
self,
|
153
|
+
) -> Times:
|
154
|
+
"""
|
155
|
+
Return the value for the attribute from class instance.
|
156
|
+
|
157
|
+
:returns: Value for the attribute from class instance.
|
158
|
+
"""
|
159
|
+
|
160
|
+
return Times(self.__start)
|
161
|
+
|
162
|
+
|
163
|
+
@property
|
164
|
+
def stop(
|
165
|
+
self,
|
166
|
+
) -> Times:
|
167
|
+
"""
|
168
|
+
Return the value for the attribute from class instance.
|
169
|
+
|
170
|
+
:returns: Value for the attribute from class instance.
|
171
|
+
"""
|
172
|
+
|
173
|
+
return Times(self.__stop)
|
174
|
+
|
175
|
+
|
176
|
+
@property
|
177
|
+
def sqlite(
|
178
|
+
self,
|
179
|
+
) -> Connection:
|
180
|
+
"""
|
181
|
+
Return the value for the attribute from class instance.
|
182
|
+
|
183
|
+
:returns: Value for the attribute from class instance.
|
184
|
+
"""
|
185
|
+
|
186
|
+
return self.__sqlite
|
187
|
+
|
188
|
+
|
189
|
+
@property
|
190
|
+
def file(
|
191
|
+
self,
|
192
|
+
) -> str:
|
193
|
+
"""
|
194
|
+
Return the value for the attribute from class instance.
|
195
|
+
|
196
|
+
:returns: Value for the attribute from class instance.
|
197
|
+
"""
|
198
|
+
|
199
|
+
return self.__file
|
200
|
+
|
201
|
+
|
202
|
+
@property
|
203
|
+
def table(
|
204
|
+
self,
|
205
|
+
) -> str:
|
206
|
+
"""
|
207
|
+
Return the value for the attribute from class instance.
|
208
|
+
|
209
|
+
:returns: Value for the attribute from class instance.
|
210
|
+
"""
|
211
|
+
|
212
|
+
return self.__table
|
213
|
+
|
214
|
+
|
215
|
+
@property
|
216
|
+
def group(
|
217
|
+
self,
|
218
|
+
) -> str:
|
219
|
+
"""
|
220
|
+
Return the value for the attribute from class instance.
|
221
|
+
|
222
|
+
:returns: Value for the attribute from class instance.
|
223
|
+
"""
|
224
|
+
|
225
|
+
return self.__group
|
226
|
+
|
227
|
+
|
228
|
+
@property
|
229
|
+
def children(
|
230
|
+
self,
|
231
|
+
) -> dict[str, Window]:
|
232
|
+
"""
|
233
|
+
Return the value for the attribute from class instance.
|
234
|
+
|
235
|
+
:returns: Value for the attribute from class instance.
|
236
|
+
"""
|
237
|
+
|
238
|
+
return dict(self.__windows)
|
239
|
+
|
240
|
+
|
241
|
+
def load_children(
|
242
|
+
self,
|
243
|
+
) -> None:
|
244
|
+
"""
|
245
|
+
Construct the children instances for the primary class.
|
246
|
+
"""
|
247
|
+
|
248
|
+
params = self.__params
|
249
|
+
windows = self.__windows
|
250
|
+
|
251
|
+
start = self.__start
|
252
|
+
stop = self.__stop
|
253
|
+
|
254
|
+
sqlite = self.__sqlite
|
255
|
+
table = self.__table
|
256
|
+
group = self.__group
|
257
|
+
|
258
|
+
|
259
|
+
config = params.windows
|
260
|
+
|
261
|
+
|
262
|
+
cursor = sqlite.execute(
|
263
|
+
f"""
|
264
|
+
select * from {table}
|
265
|
+
where "group"="{group}"
|
266
|
+
order by "unique" asc
|
267
|
+
""") # noqa: LIT003
|
268
|
+
|
269
|
+
records = cursor.fetchall()
|
270
|
+
|
271
|
+
for record in records:
|
272
|
+
|
273
|
+
unique = record[1]
|
274
|
+
next = record[3]
|
275
|
+
|
276
|
+
if unique not in config:
|
277
|
+
continue
|
278
|
+
|
279
|
+
_config = config[unique]
|
280
|
+
|
281
|
+
_config.start = next
|
282
|
+
_config.anchor = next
|
283
|
+
|
284
|
+
|
285
|
+
items = config.items()
|
286
|
+
|
287
|
+
for key, value in items:
|
288
|
+
|
289
|
+
if key in windows:
|
290
|
+
|
291
|
+
window = windows[key]
|
292
|
+
|
293
|
+
window.update(
|
294
|
+
value.start)
|
295
|
+
|
296
|
+
continue
|
297
|
+
|
298
|
+
_start = (
|
299
|
+
value.start or start)
|
300
|
+
|
301
|
+
_stop = (
|
302
|
+
value.stop or stop)
|
303
|
+
|
304
|
+
if _start < start:
|
305
|
+
_start = start
|
306
|
+
|
307
|
+
if _stop > stop:
|
308
|
+
_stop = stop
|
309
|
+
|
310
|
+
_anchor = (
|
311
|
+
value.anchor or _start)
|
312
|
+
|
313
|
+
window = Window(
|
314
|
+
value.window,
|
315
|
+
start=_start,
|
316
|
+
stop=_stop,
|
317
|
+
anchor=_anchor,
|
318
|
+
delay=value.delay)
|
319
|
+
|
320
|
+
windows[key] = window
|
321
|
+
|
322
|
+
|
323
|
+
self.__windows = windows
|
324
|
+
|
325
|
+
|
326
|
+
def save_children(
|
327
|
+
self,
|
328
|
+
) -> None:
|
329
|
+
"""
|
330
|
+
Save the child caches from the attribute into database.
|
331
|
+
"""
|
332
|
+
|
333
|
+
windows = self.__windows
|
334
|
+
|
335
|
+
sqlite = self.__sqlite
|
336
|
+
table = self.__table
|
337
|
+
group = self.__group
|
338
|
+
|
339
|
+
|
340
|
+
insert = tuple[
|
341
|
+
str, # group
|
342
|
+
str, # unique
|
343
|
+
str, # last
|
344
|
+
str, # next
|
345
|
+
str] # update
|
346
|
+
|
347
|
+
inserts: list[insert] = []
|
348
|
+
|
349
|
+
items = windows.items()
|
350
|
+
|
351
|
+
for unique, window in items:
|
352
|
+
|
353
|
+
append = (
|
354
|
+
group, unique,
|
355
|
+
window.last.subsec,
|
356
|
+
window.next.subsec,
|
357
|
+
Times('now').subsec)
|
358
|
+
|
359
|
+
inserts.append(append)
|
360
|
+
|
361
|
+
|
362
|
+
statement = (
|
363
|
+
f"""
|
364
|
+
replace into {table}
|
365
|
+
("group", "unique",
|
366
|
+
"next", "last",
|
367
|
+
"update")
|
368
|
+
values (?, ?, ?, ?, ?)
|
369
|
+
""") # noqa: LIT003
|
370
|
+
|
371
|
+
sqlite.executemany(
|
372
|
+
statement,
|
373
|
+
tuple(sorted(inserts)))
|
374
|
+
|
375
|
+
sqlite.commit()
|
376
|
+
|
377
|
+
|
378
|
+
def ready(
|
379
|
+
self,
|
380
|
+
unique: str,
|
381
|
+
update: bool = True,
|
382
|
+
) -> bool:
|
383
|
+
"""
|
384
|
+
Determine whether or not the appropriate time has passed.
|
385
|
+
|
386
|
+
:param unique: Unique identifier for the related child.
|
387
|
+
:param update: Determines whether or not time is updated.
|
388
|
+
:returns: Boolean indicating whether enough time passed.
|
389
|
+
"""
|
390
|
+
|
391
|
+
windows = self.__windows
|
392
|
+
|
393
|
+
if unique not in windows:
|
394
|
+
raise ValueError('unique')
|
395
|
+
|
396
|
+
window = windows[unique]
|
397
|
+
|
398
|
+
ready = window.ready(update)
|
399
|
+
|
400
|
+
if ready is True:
|
401
|
+
self.save_children()
|
402
|
+
|
403
|
+
return ready
|
404
|
+
|
405
|
+
|
406
|
+
def create(
|
407
|
+
self,
|
408
|
+
unique: str,
|
409
|
+
params: 'WindowParams',
|
410
|
+
) -> Window:
|
411
|
+
"""
|
412
|
+
Create a new window using the provided input parameters.
|
413
|
+
|
414
|
+
:param unique: Unique identifier for the related child.
|
415
|
+
:param params: Parameters for instantiating the instance.
|
416
|
+
:returns: Newly constructed instance of related class.
|
417
|
+
"""
|
418
|
+
|
419
|
+
windows = self.params.windows
|
420
|
+
|
421
|
+
if unique in windows:
|
422
|
+
raise ValueError('unique')
|
423
|
+
|
424
|
+
windows[unique] = params
|
425
|
+
|
426
|
+
self.load_children()
|
427
|
+
|
428
|
+
self.save_children()
|
429
|
+
|
430
|
+
return self.children[unique]
|
431
|
+
|
432
|
+
|
433
|
+
def update(
|
434
|
+
self,
|
435
|
+
unique: str,
|
436
|
+
value: Optional[PARSABLE] = None,
|
437
|
+
) -> None:
|
438
|
+
"""
|
439
|
+
Update the window from the provided parasable time value.
|
440
|
+
|
441
|
+
:param unique: Unique identifier for the related child.
|
442
|
+
:param value: Override the time updated for window value.
|
443
|
+
"""
|
444
|
+
|
445
|
+
windows = self.__windows
|
446
|
+
|
447
|
+
if unique not in windows:
|
448
|
+
raise ValueError('unique')
|
449
|
+
|
450
|
+
window = windows[unique]
|
451
|
+
|
452
|
+
self.save_children()
|
453
|
+
|
454
|
+
return window.update(value)
|
455
|
+
|
456
|
+
|
457
|
+
def delete(
|
458
|
+
self,
|
459
|
+
unique: str,
|
460
|
+
) -> None:
|
461
|
+
"""
|
462
|
+
Delete the window from the internal dictionary reference.
|
463
|
+
|
464
|
+
:param unique: Unique identifier for the related child.
|
465
|
+
"""
|
466
|
+
|
467
|
+
windows = self.__windows
|
468
|
+
|
469
|
+
if unique not in windows:
|
470
|
+
raise ValueError('unique')
|
471
|
+
|
472
|
+
del windows[unique]
|
encommon/types/notate.py
CHANGED
@@ -208,7 +208,6 @@ def _setpath(
|
|
208
208
|
:param path: Path to the value within the source object.
|
209
209
|
:param value: Value which will be defined at noted point.
|
210
210
|
:param delim: Override default delimiter between parts.
|
211
|
-
:returns: Original provided source containing the value.
|
212
211
|
"""
|
213
212
|
|
214
213
|
|
@@ -285,7 +284,6 @@ def _setvalue(
|
|
285
284
|
:param path: Path to the value within the source object.
|
286
285
|
:param value: Value which will be defined at noted point.
|
287
286
|
:param delim: Override default delimiter between parts.
|
288
|
-
:returns: Original provided source containing the value.
|
289
287
|
"""
|
290
288
|
|
291
289
|
|
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
|
encommon/utils/common.py
CHANGED
@@ -31,42 +31,3 @@ REPLACE = Union[
|
|
31
31
|
dict[str, str],
|
32
32
|
dict[str | Path, str],
|
33
33
|
dict[Path, str]]
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
def read_text(
|
38
|
-
path: str | Path,
|
39
|
-
) -> str:
|
40
|
-
"""
|
41
|
-
Read the text content from within the provided file path.
|
42
|
-
|
43
|
-
:param path: Complete or relative path to the text file.
|
44
|
-
:returns: Text content that was read from the file path.
|
45
|
-
"""
|
46
|
-
|
47
|
-
path = Path(path).resolve()
|
48
|
-
|
49
|
-
return path.read_text(
|
50
|
-
encoding='utf-8')
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
def save_text(
|
55
|
-
path: str | Path,
|
56
|
-
content: str,
|
57
|
-
) -> str:
|
58
|
-
"""
|
59
|
-
Save the provided text content to the provided file path.
|
60
|
-
|
61
|
-
:param path: Complete or relative path to the text file.
|
62
|
-
:param content: Content that will be written to the file.
|
63
|
-
:returns: Text content that was read from the file path.
|
64
|
-
"""
|
65
|
-
|
66
|
-
path = Path(path).resolve()
|
67
|
-
|
68
|
-
path.write_text(
|
69
|
-
data=content,
|
70
|
-
encoding='utf-8')
|
71
|
-
|
72
|
-
return read_text(path)
|
encommon/utils/files.py
ADDED
@@ -0,0 +1,71 @@
|
|
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 pathlib import Path
|
11
|
+
|
12
|
+
|
13
|
+
|
14
|
+
def read_text(
|
15
|
+
path: str | Path,
|
16
|
+
) -> str:
|
17
|
+
"""
|
18
|
+
Read the text content from within the provided file path.
|
19
|
+
|
20
|
+
.. testsetup::
|
21
|
+
>>> tmpdir = getfixture('tmpdir')
|
22
|
+
>>> path = Path(f'{tmpdir}/text.txt')
|
23
|
+
|
24
|
+
Example
|
25
|
+
-------
|
26
|
+
>>> save_text(path, 'foo')
|
27
|
+
'foo'
|
28
|
+
>>> read_text(path)
|
29
|
+
'foo'
|
30
|
+
|
31
|
+
:param path: Complete or relative path to the text file.
|
32
|
+
:returns: Text content that was read from the file path.
|
33
|
+
"""
|
34
|
+
|
35
|
+
path = Path(path).resolve()
|
36
|
+
|
37
|
+
return path.read_text(
|
38
|
+
encoding='utf-8')
|
39
|
+
|
40
|
+
|
41
|
+
|
42
|
+
def save_text(
|
43
|
+
path: str | Path,
|
44
|
+
content: str,
|
45
|
+
) -> str:
|
46
|
+
"""
|
47
|
+
Save the provided text content to the provided file path.
|
48
|
+
|
49
|
+
.. testsetup::
|
50
|
+
>>> tmpdir = getfixture('tmpdir')
|
51
|
+
>>> path = Path(f'{tmpdir}/text.txt')
|
52
|
+
|
53
|
+
Example
|
54
|
+
-------
|
55
|
+
>>> save_text(path, 'foo')
|
56
|
+
'foo'
|
57
|
+
>>> read_text(path)
|
58
|
+
'foo'
|
59
|
+
|
60
|
+
:param path: Complete or relative path to the text file.
|
61
|
+
:param content: Content that will be written to the file.
|
62
|
+
:returns: Text content that was read from the file path.
|
63
|
+
"""
|
64
|
+
|
65
|
+
path = Path(path).resolve()
|
66
|
+
|
67
|
+
path.write_text(
|
68
|
+
data=content,
|
69
|
+
encoding='utf-8')
|
70
|
+
|
71
|
+
return read_text(path)
|
encommon/utils/paths.py
CHANGED
@@ -110,7 +110,7 @@ def stats_path(
|
|
110
110
|
Collect stats object for the complete or relative path.
|
111
111
|
|
112
112
|
.. testsetup::
|
113
|
-
>>> from . import save_text
|
113
|
+
>>> from .files import save_text
|
114
114
|
>>> path = Path(getfixture('tmpdir'))
|
115
115
|
>>> file = path.joinpath('hello.txt')
|
116
116
|
>>> save_text(file, 'Hello world!')
|
encommon/utils/sample.py
CHANGED
@@ -15,8 +15,8 @@ from typing import Callable
|
|
15
15
|
from typing import Optional
|
16
16
|
from typing import TYPE_CHECKING
|
17
17
|
|
18
|
-
from . import read_text
|
19
|
-
from . import save_text
|
18
|
+
from .files import read_text
|
19
|
+
from .files import save_text
|
20
20
|
|
21
21
|
if TYPE_CHECKING:
|
22
22
|
from .common import REPLACE
|
@@ -76,12 +76,13 @@ def test_stats_path() -> None:
|
|
76
76
|
assert list(stats) == [
|
77
77
|
'/utils/__init__.py',
|
78
78
|
'/utils/common.py',
|
79
|
+
'/utils/files.py',
|
79
80
|
'/utils/match.py',
|
80
81
|
'/utils/paths.py',
|
81
82
|
'/utils/sample.py',
|
82
83
|
'/utils/stdout.py',
|
83
84
|
'/utils/test/__init__.py',
|
84
|
-
'/utils/test/
|
85
|
+
'/utils/test/test_files.py',
|
85
86
|
'/utils/test/test_match.py',
|
86
87
|
'/utils/test/test_paths.py',
|
87
88
|
'/utils/test/test_sample.py',
|
encommon/version.txt
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.11.1
|