dcicutils 8.8.3.1b3__py3-none-any.whl → 8.8.3.1b5__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.
- dcicutils/misc_utils.py +23 -0
- dcicutils/progress_bar.py +29 -13
- {dcicutils-8.8.3.1b3.dist-info → dcicutils-8.8.3.1b5.dist-info}/METADATA +1 -1
- {dcicutils-8.8.3.1b3.dist-info → dcicutils-8.8.3.1b5.dist-info}/RECORD +7 -7
- {dcicutils-8.8.3.1b3.dist-info → dcicutils-8.8.3.1b5.dist-info}/LICENSE.txt +0 -0
- {dcicutils-8.8.3.1b3.dist-info → dcicutils-8.8.3.1b5.dist-info}/WHEEL +0 -0
- {dcicutils-8.8.3.1b3.dist-info → dcicutils-8.8.3.1b5.dist-info}/entry_points.txt +0 -0
dcicutils/misc_utils.py
CHANGED
@@ -2548,6 +2548,29 @@ def normalize_spaces(value: str) -> str:
|
|
2548
2548
|
return re.sub(r"\s+", " ", value).strip()
|
2549
2549
|
|
2550
2550
|
|
2551
|
+
def find_nth_from_end(string: str, substring: str, nth: int) -> int:
|
2552
|
+
"""
|
2553
|
+
Returns the index of the nth occurrence of the given substring within
|
2554
|
+
the given string from the END of the given string; or -1 if not found.
|
2555
|
+
"""
|
2556
|
+
index = -1
|
2557
|
+
string = string[::-1]
|
2558
|
+
for i in range(0, nth):
|
2559
|
+
index = string.find(substring, index + 1)
|
2560
|
+
return len(string) - index - 1 if index >= 0 else -1
|
2561
|
+
|
2562
|
+
|
2563
|
+
def set_nth(string: str, nth: int, replacement: str) -> str:
|
2564
|
+
"""
|
2565
|
+
Sets the nth character of the given string to the given replacement string.
|
2566
|
+
"""
|
2567
|
+
if not isinstance(string, str) or not isinstance(nth, int) or not isinstance(replacement, str):
|
2568
|
+
return string
|
2569
|
+
if nth < 0:
|
2570
|
+
nth += len(string)
|
2571
|
+
return string[:nth] + replacement + string[nth + 1:] if 0 <= nth < len(string) else string
|
2572
|
+
|
2573
|
+
|
2551
2574
|
class JsonLinesReader:
|
2552
2575
|
|
2553
2576
|
def __init__(self, fp, padded=False, padding=None):
|
dcicutils/progress_bar.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
from collections import namedtuple
|
2
|
+
import re
|
2
3
|
from signal import signal, SIGINT
|
3
4
|
import sys
|
4
5
|
import threading
|
@@ -8,6 +9,7 @@ from types import FrameType as frame
|
|
8
9
|
from typing import Callable, List, Optional, Union
|
9
10
|
from contextlib import contextmanager
|
10
11
|
from dcicutils.command_utils import yes_or_no
|
12
|
+
from dcicutils.misc_utils import find_nth_from_end, set_nth
|
11
13
|
|
12
14
|
|
13
15
|
class TQDM(tqdm):
|
@@ -259,32 +261,29 @@ class ProgressBar:
|
|
259
261
|
# string in the display string where the progress bar should actually go,
|
260
262
|
# which we do in _format_description. Other minor things too; see below.
|
261
263
|
sys_stdout_write = sys.stdout.write
|
262
|
-
|
263
|
-
progress_most_recent = None
|
264
|
-
description_most_recent = None
|
264
|
+
last_total = None ; last_progress = None ; last_text = None # noqa
|
265
265
|
def tidy_stdout_write(text: str) -> None: # noqa
|
266
266
|
nonlocal self, sys_stdout_write, sentinel_internal, spina, spini, spinn
|
267
|
-
nonlocal
|
267
|
+
nonlocal last_total, last_progress, last_text
|
268
268
|
def replace_first(value: str, match: str, replacement: str) -> str: # noqa
|
269
269
|
return value[:i] + replacement + value[i + len(match):] if (i := value.find(match)) >= 0 else value
|
270
270
|
def remove_extra_trailing_spaces(text: str) -> str: # noqa
|
271
271
|
while text.endswith(" "):
|
272
272
|
text = text[:-1]
|
273
273
|
return text
|
274
|
-
if not text
|
274
|
+
if not text:
|
275
275
|
return
|
276
|
-
if
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
description_most_recent = self._description
|
276
|
+
if self._bar:
|
277
|
+
if ((self._bar.total == last_total) and (self._bar.n == last_progress) and (last_text == text)):
|
278
|
+
return
|
279
|
+
last_total = self._bar.total ; last_progress = self._bar.n ; last_text = text # noqa
|
281
280
|
if (self._disabled or self._done) and sentinel_internal in text:
|
282
281
|
# Another hack to really disable output on interrupt; in this case we set
|
283
282
|
# tqdm.disable to True, but output can still dribble out, so if the output
|
284
283
|
# looks like it is from tqdm and we are disabled/done then do no output.
|
285
284
|
return
|
286
285
|
if sentinel_internal in text:
|
287
|
-
spinc = spina[spini % spinn] if not ("100%|" in text) else "
|
286
|
+
spinc = spina[spini % spinn] if not ("100%|" in text) else "✓" ; spini += 1 # noqa
|
288
287
|
text = replace_first(text, sentinel_internal, f" {spinc}")
|
289
288
|
text = replace_first(text, "%|", "% ◀|")
|
290
289
|
text = remove_extra_trailing_spaces(text)
|
@@ -293,9 +292,26 @@ class ProgressBar:
|
|
293
292
|
# the unit we gave, which is empty; idunno; just replace it here.
|
294
293
|
text = replace_first(text, "s/ ", "/s ")
|
295
294
|
sys_stdout_write(text)
|
296
|
-
if self._captured_output_for_testing is not None:
|
297
|
-
self._captured_output_for_testing.append(text)
|
298
295
|
sys.stdout.flush()
|
296
|
+
if self._captured_output_for_testing is not None:
|
297
|
+
# For testing only we replace vacilliting values in the out like rate,
|
298
|
+
# time elapsed, and ETA with static values; so that something like this:
|
299
|
+
# > Working / 20% ◀|█████████▌ | 1/5 | 536.00/s | 00:01 | ETA: 00:02
|
300
|
+
# becomes something more static like this after calling this function:
|
301
|
+
# > Working | 20% ◀|### | 1/5 | 0.0/s | 00:00 | ETA: 00:00
|
302
|
+
# This function obviously has intimate knowledge of the output; better here than in tests.
|
303
|
+
def replace_vacillating_values_with_static(text: str) -> str:
|
304
|
+
blocks = "\u2587|\u2588|\u2589|\u258a|\u258b|\u258c|\u258d|\u258e|\u258f"
|
305
|
+
if (n := find_nth_from_end(text, "|", 5)) >= 8:
|
306
|
+
pattern = re.compile(
|
307
|
+
rf"(\s*)(\d*%? ◀\|)(?:\s*{blocks}|#)*\s*(\|\s*\d+/\d+)?(\s*\|\s*)"
|
308
|
+
rf"(?:\d+\.?\d*|\?)(\/s\s*\|\s*)(?:\d+:\d+)?(\s*\|\s*ETA:\s*)(?:\d+:\d+|\?)?")
|
309
|
+
if match := pattern.match(text[n - 6:]):
|
310
|
+
if text[n - 8:n - 7] != "✓": text = set_nth(text, n - 8, "|") # noqa
|
311
|
+
return (text[0:n - 6].replace("\r", "") +
|
312
|
+
match.expand(rf"\g<1>\g<2>### \g<3>\g<4>0.0\g<5>00:00\g<6>00:00"))
|
313
|
+
return text
|
314
|
+
self._captured_output_for_testing.append(replace_vacillating_values_with_static(text))
|
299
315
|
def restore_stdout_write() -> None: # noqa
|
300
316
|
nonlocal sys_stdout_write
|
301
317
|
if sys_stdout_write is not None:
|
@@ -43,12 +43,12 @@ dcicutils/license_policies/park-lab-gpl-pipeline.jsonc,sha256=vLZkwm3Js-kjV44nug
|
|
43
43
|
dcicutils/license_policies/park-lab-pipeline.jsonc,sha256=9qlY0ASy3iUMQlr3gorVcXrSfRHnVGbLhkS427UaRy4,283
|
44
44
|
dcicutils/license_utils.py,sha256=d1cq6iwv5Ju-VjdoINi6q7CPNNL7Oz6rcJdLMY38RX0,46978
|
45
45
|
dcicutils/log_utils.py,sha256=7pWMc6vyrorUZQf-V-M3YC6zrPgNhuV_fzm9xqTPph0,10883
|
46
|
-
dcicutils/misc_utils.py,sha256=
|
46
|
+
dcicutils/misc_utils.py,sha256=a_grjJdiYgEMctwnXy7uDoFtDvCfAv1gjrLxdrOkptM,103041
|
47
47
|
dcicutils/obfuscation_utils.py,sha256=fo2jOmDRC6xWpYX49u80bVNisqRRoPskFNX3ymFAmjw,5963
|
48
48
|
dcicutils/opensearch_utils.py,sha256=V2exmFYW8Xl2_pGFixF4I2Cc549Opwe4PhFi5twC0M8,1017
|
49
49
|
dcicutils/portal_object_utils.py,sha256=gDXRgPsRvqCFwbC8WatsuflAxNiigOnqr0Hi93k3AgE,15422
|
50
50
|
dcicutils/portal_utils.py,sha256=Xm0IqL2dA9C2gx98cPEbvlo81V76bEmpUpxb_8S3VqM,30480
|
51
|
-
dcicutils/progress_bar.py,sha256=
|
51
|
+
dcicutils/progress_bar.py,sha256=BWd-a1Og7SL_FNtIQv8gAkGYMyp6VgwIwTlLClsl-8g,15988
|
52
52
|
dcicutils/project_utils.py,sha256=qPdCaFmWUVBJw4rw342iUytwdQC0P-XKpK4mhyIulMM,31250
|
53
53
|
dcicutils/qa_checkers.py,sha256=cdXjeL0jCDFDLT8VR8Px78aS10hwNISOO5G_Zv2TZ6M,20534
|
54
54
|
dcicutils/qa_utils.py,sha256=TT0SiJWiuxYvbsIyhK9VO4uV_suxhB6CpuC4qPacCzQ,160208
|
@@ -72,8 +72,8 @@ dcicutils/trace_utils.py,sha256=g8kwV4ebEy5kXW6oOrEAUsurBcCROvwtZqz9fczsGRE,1769
|
|
72
72
|
dcicutils/validation_utils.py,sha256=cMZIU2cY98FYtzK52z5WUYck7urH6JcqOuz9jkXpqzg,14797
|
73
73
|
dcicutils/variant_utils.py,sha256=2H9azNx3xAj-MySg-uZ2SFqbWs4kZvf61JnK6b-h4Qw,4343
|
74
74
|
dcicutils/zip_utils.py,sha256=rnjNv_k6L9jT2SjDSgVXp4BEJYLtz9XN6Cl2Fy-tqnM,2027
|
75
|
-
dcicutils-8.8.3.
|
76
|
-
dcicutils-8.8.3.
|
77
|
-
dcicutils-8.8.3.
|
78
|
-
dcicutils-8.8.3.
|
79
|
-
dcicutils-8.8.3.
|
75
|
+
dcicutils-8.8.3.1b5.dist-info/LICENSE.txt,sha256=qnwSmfnEWMl5l78VPDEzAmEbLVrRqQvfUQiHT0ehrOo,1102
|
76
|
+
dcicutils-8.8.3.1b5.dist-info/METADATA,sha256=Z9Not6bJDezXyZb3afrGADA6mRDuOd2QbETxSbht6DM,3356
|
77
|
+
dcicutils-8.8.3.1b5.dist-info/WHEEL,sha256=7Z8_27uaHI_UZAc4Uox4PpBhQ9Y5_modZXWMxtUi4NU,88
|
78
|
+
dcicutils-8.8.3.1b5.dist-info/entry_points.txt,sha256=51Q4F_2V10L0282W7HFjP4jdzW4K8lnWDARJQVFy_hw,270
|
79
|
+
dcicutils-8.8.3.1b5.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|