encommon 0.7.6__py3-none-any.whl → 0.8.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.
- encommon/config/__init__.py +4 -0
- encommon/config/common.py +18 -14
- encommon/config/config.py +8 -5
- encommon/config/files.py +13 -7
- encommon/config/logger.py +94 -88
- encommon/config/params.py +1 -1
- encommon/config/paths.py +16 -8
- encommon/config/test/test_common.py +27 -4
- encommon/config/test/test_config.py +48 -82
- encommon/config/test/test_files.py +58 -43
- encommon/config/test/test_logger.py +129 -82
- encommon/config/test/test_paths.py +70 -30
- encommon/conftest.py +52 -12
- encommon/crypts/__init__.py +2 -0
- encommon/crypts/crypts.py +3 -1
- encommon/crypts/hashes.py +2 -2
- encommon/crypts/test/test_crypts.py +50 -28
- encommon/crypts/test/test_hashes.py +20 -18
- encommon/times/__init__.py +2 -0
- encommon/times/common.py +99 -15
- encommon/times/duration.py +50 -36
- encommon/times/parse.py +13 -25
- encommon/times/test/test_common.py +47 -16
- encommon/times/test/test_duration.py +104 -79
- encommon/times/test/test_parse.py +53 -63
- encommon/times/test/test_timers.py +90 -36
- encommon/times/test/test_times.py +21 -30
- encommon/times/test/test_window.py +73 -21
- encommon/times/timers.py +91 -58
- encommon/times/times.py +36 -34
- encommon/times/window.py +4 -4
- encommon/types/dicts.py +10 -4
- encommon/types/empty.py +7 -2
- encommon/types/strings.py +10 -0
- encommon/types/test/test_dicts.py +5 -5
- encommon/types/test/test_empty.py +4 -1
- encommon/types/test/test_strings.py +1 -1
- encommon/utils/__init__.py +4 -0
- encommon/utils/common.py +51 -6
- encommon/utils/match.py +1 -0
- encommon/utils/paths.py +42 -23
- encommon/utils/sample.py +31 -27
- encommon/utils/stdout.py +28 -17
- encommon/utils/test/test_common.py +35 -0
- encommon/utils/test/test_paths.py +3 -2
- encommon/utils/test/test_sample.py +28 -12
- encommon/version.txt +1 -1
- {encommon-0.7.6.dist-info → encommon-0.8.0.dist-info}/METADATA +1 -1
- encommon-0.8.0.dist-info/RECORD +63 -0
- encommon-0.7.6.dist-info/RECORD +0 -62
- {encommon-0.7.6.dist-info → encommon-0.8.0.dist-info}/LICENSE +0 -0
- {encommon-0.7.6.dist-info → encommon-0.8.0.dist-info}/WHEEL +0 -0
- {encommon-0.7.6.dist-info → encommon-0.8.0.dist-info}/top_level.txt +0 -0
encommon/times/timers.py
CHANGED
@@ -20,10 +20,9 @@ if TYPE_CHECKING:
|
|
20
20
|
|
21
21
|
|
22
22
|
|
23
|
-
|
23
|
+
CACHE_TABLE = (
|
24
24
|
"""
|
25
|
-
create table
|
26
|
-
if not exists
|
25
|
+
create table if not exists
|
27
26
|
{0} (
|
28
27
|
"unique" text not null,
|
29
28
|
"update" text not null,
|
@@ -32,6 +31,11 @@ TABLE = (
|
|
32
31
|
|
33
32
|
|
34
33
|
|
34
|
+
_TIMERS = dict[str, float]
|
35
|
+
_CACHED = dict[str, Times]
|
36
|
+
|
37
|
+
|
38
|
+
|
35
39
|
class Timers:
|
36
40
|
"""
|
37
41
|
Track timers on unique key and determine when to proceed.
|
@@ -53,51 +57,57 @@ class Timers:
|
|
53
57
|
True
|
54
58
|
|
55
59
|
:param timers: Seconds that are used for each of timers.
|
56
|
-
:param
|
60
|
+
:param file: Optional path to SQLite database for
|
57
61
|
cache. This will allow for use between executions.
|
58
|
-
:param
|
62
|
+
:param table: Optional override default table name.
|
59
63
|
"""
|
60
64
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
+
__config: _TIMERS
|
66
|
+
__sqlite: 'Connection'
|
67
|
+
__file: str
|
68
|
+
__table: str
|
69
|
+
__cache: _CACHED
|
65
70
|
|
66
71
|
|
67
72
|
def __init__(
|
68
73
|
self,
|
69
74
|
timers: Optional[dict[str, NUMERIC]] = None,
|
70
|
-
|
71
|
-
|
75
|
+
file: str = ':memory:',
|
76
|
+
table: str = 'timers',
|
72
77
|
) -> None:
|
73
78
|
"""
|
74
79
|
Initialize instance for class using provided parameters.
|
75
80
|
"""
|
76
81
|
|
77
|
-
timers = timers or {}
|
78
82
|
|
83
|
+
timers = dict(timers or {})
|
79
84
|
|
80
|
-
|
81
|
-
k: float(v)
|
82
|
-
for k, v in
|
83
|
-
timers.items()}
|
85
|
+
items = timers.items()
|
84
86
|
|
87
|
+
for key, value in items:
|
88
|
+
timers[key] = float(value)
|
85
89
|
|
86
|
-
cached = SQLite(cache_file)
|
87
90
|
|
88
|
-
|
89
|
-
TABLE.format(cache_name))
|
91
|
+
sqlite = SQLite(file)
|
90
92
|
|
91
|
-
|
93
|
+
sqlite.execute(
|
94
|
+
CACHE_TABLE
|
95
|
+
.format(table))
|
96
|
+
|
97
|
+
sqlite.commit()
|
98
|
+
|
99
|
+
|
100
|
+
cached: _CACHED = {}
|
92
101
|
|
93
|
-
|
94
|
-
|
102
|
+
for timer in timers:
|
103
|
+
cached[timer] = Times()
|
95
104
|
|
96
105
|
|
97
|
-
self.
|
98
|
-
|
99
|
-
|
100
|
-
|
106
|
+
self.__config = timers
|
107
|
+
self.__sqlite = sqlite
|
108
|
+
self.__file = file
|
109
|
+
self.__table = table
|
110
|
+
self.__cache = cached
|
101
111
|
|
102
112
|
|
103
113
|
self.load_cache()
|
@@ -111,9 +121,9 @@ class Timers:
|
|
111
121
|
Load the timers cache from the database into attribute.
|
112
122
|
"""
|
113
123
|
|
114
|
-
cached = self.
|
115
|
-
table = self.
|
116
|
-
cachem = self.
|
124
|
+
cached = self.__sqlite
|
125
|
+
table = self.__table
|
126
|
+
cachem = self.__cache
|
117
127
|
|
118
128
|
cursor = cached.execute(
|
119
129
|
f'select * from {table}'
|
@@ -138,19 +148,29 @@ class Timers:
|
|
138
148
|
Save the timers cache from the attribute into database.
|
139
149
|
"""
|
140
150
|
|
141
|
-
|
142
|
-
|
143
|
-
|
151
|
+
insert = tuple[str, str]
|
152
|
+
inserts: list[insert] = []
|
153
|
+
|
154
|
+
|
155
|
+
cached = self.__sqlite
|
156
|
+
table = self.__table
|
157
|
+
cachem = self.__cache
|
158
|
+
|
159
|
+
|
160
|
+
items = cachem.items()
|
161
|
+
|
162
|
+
for key, value in items:
|
163
|
+
|
164
|
+
append = (key, str(value))
|
165
|
+
|
166
|
+
inserts.append(append)
|
144
167
|
|
145
|
-
insert = [
|
146
|
-
(k, str(v)) for k, v
|
147
|
-
in cachem.items()]
|
148
168
|
|
149
169
|
cached.executemany(
|
150
170
|
(f'replace into {table}'
|
151
171
|
' ("unique", "update")'
|
152
172
|
' values (?, ?)'),
|
153
|
-
tuple(
|
173
|
+
tuple(sorted(inserts)))
|
154
174
|
|
155
175
|
cached.commit()
|
156
176
|
|
@@ -158,18 +178,18 @@ class Timers:
|
|
158
178
|
@property
|
159
179
|
def timers(
|
160
180
|
self,
|
161
|
-
) ->
|
181
|
+
) -> _TIMERS:
|
162
182
|
"""
|
163
183
|
Return the value for the attribute from class instance.
|
164
184
|
|
165
185
|
:returns: Value for the attribute from class instance.
|
166
186
|
"""
|
167
187
|
|
168
|
-
return dict(self.
|
188
|
+
return dict(self.__config)
|
169
189
|
|
170
190
|
|
171
191
|
@property
|
172
|
-
def
|
192
|
+
def sqlite(
|
173
193
|
self,
|
174
194
|
) -> 'Connection':
|
175
195
|
"""
|
@@ -178,24 +198,24 @@ class Timers:
|
|
178
198
|
:returns: Value for the attribute from class instance.
|
179
199
|
"""
|
180
200
|
|
181
|
-
return self.
|
201
|
+
return self.__sqlite
|
182
202
|
|
183
203
|
|
184
204
|
@property
|
185
|
-
def
|
205
|
+
def file(
|
186
206
|
self,
|
187
|
-
) ->
|
207
|
+
) -> str:
|
188
208
|
"""
|
189
209
|
Return the value for the attribute from class instance.
|
190
210
|
|
191
211
|
:returns: Value for the attribute from class instance.
|
192
212
|
"""
|
193
213
|
|
194
|
-
return
|
214
|
+
return self.__file
|
195
215
|
|
196
216
|
|
197
217
|
@property
|
198
|
-
def
|
218
|
+
def table(
|
199
219
|
self,
|
200
220
|
) -> str:
|
201
221
|
"""
|
@@ -204,7 +224,20 @@ class Timers:
|
|
204
224
|
:returns: Value for the attribute from class instance.
|
205
225
|
"""
|
206
226
|
|
207
|
-
return self.
|
227
|
+
return self.__table
|
228
|
+
|
229
|
+
|
230
|
+
@property
|
231
|
+
def cache(
|
232
|
+
self,
|
233
|
+
) -> _CACHED:
|
234
|
+
"""
|
235
|
+
Return the value for the attribute from class instance.
|
236
|
+
|
237
|
+
:returns: Value for the attribute from class instance.
|
238
|
+
"""
|
239
|
+
|
240
|
+
return dict(self.__cache)
|
208
241
|
|
209
242
|
|
210
243
|
def ready(
|
@@ -219,18 +252,18 @@ class Timers:
|
|
219
252
|
For performance reasons, this method will not notice
|
220
253
|
changes within the database unless refreshed first.
|
221
254
|
|
222
|
-
:param unique:
|
255
|
+
:param unique: Which timer configuration from reference.
|
223
256
|
:param update: Determines whether or not time is updated.
|
224
257
|
"""
|
225
258
|
|
226
|
-
|
227
|
-
caches = self.
|
259
|
+
config = self.__config
|
260
|
+
caches = self.__cache
|
228
261
|
|
229
262
|
if unique not in caches:
|
230
263
|
raise ValueError('unique')
|
231
264
|
|
232
265
|
cache = caches[unique]
|
233
|
-
timer =
|
266
|
+
timer = config[unique]
|
234
267
|
|
235
268
|
ready = cache.since >= timer
|
236
269
|
|
@@ -248,11 +281,11 @@ class Timers:
|
|
248
281
|
"""
|
249
282
|
Update the existing timer from mapping within the cache.
|
250
283
|
|
251
|
-
:param unique:
|
284
|
+
:param unique: Which timer configuration from reference.
|
252
285
|
:param started: Override the start time for timer value.
|
253
286
|
"""
|
254
287
|
|
255
|
-
caches = self.
|
288
|
+
caches = self.__cache
|
256
289
|
|
257
290
|
if unique not in caches:
|
258
291
|
raise ValueError('unique')
|
@@ -271,18 +304,18 @@ class Timers:
|
|
271
304
|
"""
|
272
305
|
Update the existing timer from mapping within the cache.
|
273
306
|
|
274
|
-
:param unique:
|
275
|
-
:param minimum:
|
276
|
-
:param started:
|
307
|
+
:param unique: Which timer configuration from reference.
|
308
|
+
:param minimum: Determine minimum seconds that must pass.
|
309
|
+
:param started: Determine when time starts for the timer.
|
277
310
|
"""
|
278
311
|
|
279
|
-
|
280
|
-
caches = self.
|
312
|
+
config = self.__config
|
313
|
+
caches = self.__cache
|
281
314
|
|
282
|
-
if unique in
|
315
|
+
if unique in config:
|
283
316
|
raise ValueError('unique')
|
284
317
|
|
285
|
-
|
318
|
+
config[unique] = float(minimum)
|
286
319
|
caches[unique] = Times(started)
|
287
320
|
|
288
321
|
self.save_cache()
|
encommon/times/times.py
CHANGED
@@ -7,17 +7,17 @@ is permitted, for more information consult the project license file.
|
|
7
7
|
|
8
8
|
|
9
9
|
|
10
|
+
from contextlib import suppress
|
10
11
|
from datetime import datetime
|
11
12
|
from datetime import timedelta
|
12
|
-
from datetime import timezone
|
13
13
|
from typing import Optional
|
14
14
|
|
15
|
-
from dateutil.tz import gettz
|
16
|
-
|
17
15
|
from .common import PARSABLE
|
18
16
|
from .common import STAMP_HUMAN
|
19
17
|
from .common import STAMP_SIMPLE
|
20
18
|
from .common import STAMP_SUBSEC
|
19
|
+
from .common import findtz
|
20
|
+
from .common import strftime
|
21
21
|
from .parse import parse_time
|
22
22
|
from .parse import since_time
|
23
23
|
|
@@ -40,6 +40,7 @@ class Times:
|
|
40
40
|
"""
|
41
41
|
|
42
42
|
__source: datetime
|
43
|
+
__hashed: int
|
43
44
|
|
44
45
|
|
45
46
|
def __init__(
|
@@ -54,12 +55,16 @@ class Times:
|
|
54
55
|
Initialize instance for class using provided parameters.
|
55
56
|
"""
|
56
57
|
|
57
|
-
|
58
|
+
parsed = parse_time(
|
58
59
|
source=source,
|
59
60
|
anchor=anchor,
|
60
61
|
format=format,
|
61
62
|
tzname=tzname)
|
62
63
|
|
64
|
+
self.__source = parsed
|
65
|
+
self.__hashed = int(
|
66
|
+
self.mpoch * 1000)
|
67
|
+
|
63
68
|
|
64
69
|
def __repr__(
|
65
70
|
self,
|
@@ -82,7 +87,7 @@ class Times:
|
|
82
87
|
:returns: Boolean indicating outcome from the operation.
|
83
88
|
"""
|
84
89
|
|
85
|
-
return int(self.
|
90
|
+
return int(1e9 + self.__hashed)
|
86
91
|
|
87
92
|
|
88
93
|
def __str__(
|
@@ -103,7 +108,7 @@ class Times:
|
|
103
108
|
"""
|
104
109
|
Built-in method representing numeric value for instance.
|
105
110
|
|
106
|
-
:returns: Numeric representation for
|
111
|
+
:returns: Numeric representation for value in instance.
|
107
112
|
"""
|
108
113
|
|
109
114
|
return int(self.epoch)
|
@@ -115,7 +120,7 @@ class Times:
|
|
115
120
|
"""
|
116
121
|
Built-in method representing numeric value for instance.
|
117
122
|
|
118
|
-
:returns: Numeric representation for
|
123
|
+
:returns: Numeric representation for value in instance.
|
119
124
|
"""
|
120
125
|
|
121
126
|
return float(self.epoch)
|
@@ -168,13 +173,16 @@ class Times:
|
|
168
173
|
:returns: Boolean indicating outcome from the operation.
|
169
174
|
"""
|
170
175
|
|
171
|
-
|
172
|
-
|
176
|
+
source = self.__source
|
177
|
+
|
178
|
+
with suppress(Exception):
|
173
179
|
|
174
|
-
|
175
|
-
|
180
|
+
parsed = parse_time(
|
181
|
+
other) # type: ignore
|
176
182
|
|
177
|
-
|
183
|
+
return source == parsed
|
184
|
+
|
185
|
+
return False
|
178
186
|
|
179
187
|
|
180
188
|
def __ne__(
|
@@ -278,7 +286,9 @@ class Times:
|
|
278
286
|
:returns: Seconds since the Unix epoch for the instance.
|
279
287
|
"""
|
280
288
|
|
281
|
-
|
289
|
+
source = self.__source
|
290
|
+
|
291
|
+
return source.timestamp()
|
282
292
|
|
283
293
|
|
284
294
|
@property
|
@@ -369,10 +379,10 @@ class Times:
|
|
369
379
|
:returns: Object containing time just before the time.
|
370
380
|
"""
|
371
381
|
|
372
|
-
|
373
|
-
microseconds=1)
|
382
|
+
source = self.__source
|
374
383
|
|
375
|
-
source
|
384
|
+
source -= timedelta(
|
385
|
+
microseconds=1)
|
376
386
|
|
377
387
|
return Times(source)
|
378
388
|
|
@@ -387,10 +397,10 @@ class Times:
|
|
387
397
|
:returns: Object containing time just after the time.
|
388
398
|
"""
|
389
399
|
|
390
|
-
|
391
|
-
microseconds=1)
|
400
|
+
source = self.__source
|
392
401
|
|
393
|
-
source
|
402
|
+
source += timedelta(
|
403
|
+
microseconds=1)
|
394
404
|
|
395
405
|
return Times(source)
|
396
406
|
|
@@ -409,21 +419,13 @@ class Times:
|
|
409
419
|
:returns: Timestamp using provided format for instance.
|
410
420
|
"""
|
411
421
|
|
412
|
-
|
422
|
+
source = self.__source
|
413
423
|
|
424
|
+
tzinfo = findtz(tzname)
|
414
425
|
|
415
|
-
|
416
|
-
tzinfo = gettz(tzname)
|
417
|
-
else:
|
418
|
-
tzinfo = timezone.utc
|
426
|
+
parsed = source.astimezone(tzinfo)
|
419
427
|
|
420
|
-
|
421
|
-
raise ValueError('tzname')
|
422
|
-
|
423
|
-
|
424
|
-
return datetime.strftime(
|
425
|
-
parsed.astimezone(tzinfo),
|
426
|
-
format)
|
428
|
+
return strftime(parsed, format)
|
427
429
|
|
428
430
|
|
429
431
|
def shift(
|
@@ -437,6 +439,6 @@ class Times:
|
|
437
439
|
:returns: New instance of the class using shifted time.
|
438
440
|
"""
|
439
441
|
|
440
|
-
|
441
|
-
|
442
|
-
|
442
|
+
source = self.__source
|
443
|
+
|
444
|
+
return Times(notate, anchor=source)
|
encommon/times/window.py
CHANGED
@@ -170,7 +170,7 @@ class Window:
|
|
170
170
|
|
171
171
|
|
172
172
|
@property
|
173
|
-
def
|
173
|
+
def last(
|
174
174
|
self,
|
175
175
|
) -> Times:
|
176
176
|
"""
|
@@ -179,11 +179,11 @@ class Window:
|
|
179
179
|
:returns: Value for the attribute from class instance.
|
180
180
|
"""
|
181
181
|
|
182
|
-
return Times(self.
|
182
|
+
return Times(self.__wilast)
|
183
183
|
|
184
184
|
|
185
185
|
@property
|
186
|
-
def
|
186
|
+
def next(
|
187
187
|
self,
|
188
188
|
) -> Times:
|
189
189
|
"""
|
@@ -192,7 +192,7 @@ class Window:
|
|
192
192
|
:returns: Value for the attribute from class instance.
|
193
193
|
"""
|
194
194
|
|
195
|
-
return Times(self.
|
195
|
+
return Times(self.__winext)
|
196
196
|
|
197
197
|
|
198
198
|
@property
|
encommon/types/dicts.py
CHANGED
@@ -49,12 +49,16 @@ def merge_dicts(
|
|
49
49
|
elif (isinstance(dict1[key], list)
|
50
50
|
and isinstance(value, list)
|
51
51
|
and merge_list is True):
|
52
|
-
|
52
|
+
|
53
|
+
dict1[key] = (
|
54
|
+
[] + dict1[key] + value)
|
53
55
|
|
54
56
|
elif (isinstance(dict1[key], dict)
|
55
57
|
and isinstance(value, dict)
|
56
58
|
and merge_dict is True):
|
57
|
-
|
59
|
+
|
60
|
+
merge_dicts(
|
61
|
+
dict1[key], value, force)
|
58
62
|
|
59
63
|
elif force is True:
|
60
64
|
dict1[key] = value
|
@@ -81,6 +85,8 @@ def sort_dict(
|
|
81
85
|
:returns: New dictionary with keys sorted alphabetical.
|
82
86
|
"""
|
83
87
|
|
84
|
-
|
88
|
+
items = sorted(
|
85
89
|
value.items(),
|
86
|
-
reverse=reverse)
|
90
|
+
reverse=reverse)
|
91
|
+
|
92
|
+
return dict(items)
|
encommon/types/empty.py
CHANGED
@@ -51,8 +51,13 @@ class EmptyType:
|
|
51
51
|
:returns: Same instance of class that first instantiated.
|
52
52
|
"""
|
53
53
|
|
54
|
-
|
55
|
-
|
54
|
+
empty = cls.__empty
|
55
|
+
|
56
|
+
if empty is not None:
|
57
|
+
return empty
|
58
|
+
|
59
|
+
cls.__empty = (
|
60
|
+
object.__new__(cls))
|
56
61
|
|
57
62
|
return cls.__empty
|
58
63
|
|
encommon/types/strings.py
CHANGED
@@ -14,14 +14,14 @@ from ..dicts import sort_dict
|
|
14
14
|
|
15
15
|
|
16
16
|
|
17
|
-
|
17
|
+
_DICT1 = {
|
18
18
|
'dict1': 'dict1',
|
19
19
|
'str': 'd1string',
|
20
20
|
'list': ['d1list'],
|
21
21
|
'dict': {'key': 'd1value'},
|
22
22
|
'bool': False}
|
23
23
|
|
24
|
-
|
24
|
+
_DICT2 = {
|
25
25
|
'dict2': 'dict2',
|
26
26
|
'str': 'd2string',
|
27
27
|
'list': ['d2list'],
|
@@ -35,8 +35,8 @@ def test_merge_dicts() -> None:
|
|
35
35
|
Perform various tests associated with relevant routines.
|
36
36
|
"""
|
37
37
|
|
38
|
-
dict1 = deepcopy(
|
39
|
-
dict2 = deepcopy(
|
38
|
+
dict1 = deepcopy(_DICT1)
|
39
|
+
dict2 = deepcopy(_DICT2)
|
40
40
|
|
41
41
|
dict1['recurse'] = deepcopy(dict1)
|
42
42
|
dict2['recurse'] = deepcopy(dict2)
|
@@ -114,7 +114,7 @@ def test_sort_dict() -> None:
|
|
114
114
|
Perform various tests associated with relevant routines.
|
115
115
|
"""
|
116
116
|
|
117
|
-
assert sort_dict(
|
117
|
+
assert sort_dict(_DICT1) == {
|
118
118
|
'bool': False,
|
119
119
|
'dict': {'key': 'd1value'},
|
120
120
|
'dict1': 'dict1',
|
@@ -22,15 +22,18 @@ def test_EmptyType() -> None:
|
|
22
22
|
|
23
23
|
empty = EmptyType()
|
24
24
|
|
25
|
+
|
25
26
|
attrs = list(empty.__dict__)
|
26
27
|
|
27
28
|
assert attrs == [
|
28
29
|
'_EmptyType__empty']
|
29
30
|
|
31
|
+
|
30
32
|
assert repr(empty) == 'Empty'
|
31
|
-
assert
|
33
|
+
assert hash(empty) > 0
|
32
34
|
assert str(empty) == 'Empty'
|
33
35
|
|
36
|
+
|
34
37
|
assert not (Empty or None)
|
35
38
|
assert Empty is empty
|
36
39
|
assert Empty is Empty
|
encommon/utils/__init__.py
CHANGED
@@ -7,6 +7,8 @@ is permitted, for more information consult the project license file.
|
|
7
7
|
|
8
8
|
|
9
9
|
|
10
|
+
from .common import read_text
|
11
|
+
from .common import save_text
|
10
12
|
from .match import fuzz_match
|
11
13
|
from .match import rgxp_match
|
12
14
|
from .paths import resolve_path
|
@@ -30,8 +32,10 @@ __all__ = [
|
|
30
32
|
'make_ansi',
|
31
33
|
'prep_sample',
|
32
34
|
'print_ansi',
|
35
|
+
'read_text',
|
33
36
|
'resolve_path',
|
34
37
|
'resolve_paths',
|
35
38
|
'rgxp_match',
|
39
|
+
'save_text',
|
36
40
|
'stats_path',
|
37
41
|
'strip_ansi']
|