dcicutils 8.8.3.1b1__py3-none-any.whl → 8.8.3.1b3__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/captured_output.py +18 -2
- dcicutils/progress_bar.py +28 -8
- dcicutils/structured_data.py +3 -1
- {dcicutils-8.8.3.1b1.dist-info → dcicutils-8.8.3.1b3.dist-info}/METADATA +1 -1
- {dcicutils-8.8.3.1b1.dist-info → dcicutils-8.8.3.1b3.dist-info}/RECORD +8 -8
- {dcicutils-8.8.3.1b1.dist-info → dcicutils-8.8.3.1b3.dist-info}/LICENSE.txt +0 -0
- {dcicutils-8.8.3.1b1.dist-info → dcicutils-8.8.3.1b3.dist-info}/WHEEL +0 -0
- {dcicutils-8.8.3.1b1.dist-info → dcicutils-8.8.3.1b3.dist-info}/entry_points.txt +0 -0
dcicutils/captured_output.py
CHANGED
@@ -9,7 +9,7 @@ _real_stderr = sys.stderr
|
|
9
9
|
|
10
10
|
|
11
11
|
@contextmanager
|
12
|
-
def captured_output(capture: bool = True):
|
12
|
+
def captured_output(capture: bool = True, encoding: Optional[str] = None):
|
13
13
|
"""
|
14
14
|
Context manager to capture any/all output to stdout or stderr, and not actually output it to stdout
|
15
15
|
or stderr. Yields and object with a get_captured_output() method to get the output captured thus far,
|
@@ -24,7 +24,7 @@ def captured_output(capture: bool = True):
|
|
24
24
|
|
25
25
|
original_stdout = _real_stdout
|
26
26
|
original_stderr = _real_stderr
|
27
|
-
captured_output = io.StringIO()
|
27
|
+
captured_output = io.StringIO() if not encoding else _EncodedStringIO(encoding)
|
28
28
|
|
29
29
|
def set_original_output() -> None:
|
30
30
|
sys.stdout = original_stdout
|
@@ -68,3 +68,19 @@ def uncaptured_output():
|
|
68
68
|
finally:
|
69
69
|
sys.stdout = original_stdout
|
70
70
|
sys.stderr = original_stderr
|
71
|
+
|
72
|
+
|
73
|
+
class _EncodedStringIO:
|
74
|
+
def __init__(self, encoding: str = "utf-8"):
|
75
|
+
self.encoding = encoding
|
76
|
+
self.buffer = io.BytesIO()
|
77
|
+
def write(self, s): # noqa
|
78
|
+
self.buffer.write(s.encode(self.encoding))
|
79
|
+
def flush(self): # noqa
|
80
|
+
self.buffer.flush()
|
81
|
+
def getvalue(self): # noqa
|
82
|
+
return self.buffer.getvalue().decode(self.encoding)
|
83
|
+
def __str__(self): # noqa
|
84
|
+
return self.getvalue()
|
85
|
+
def __repr__(self): # noqa
|
86
|
+
return repr(self.getvalue())
|
dcicutils/progress_bar.py
CHANGED
@@ -5,7 +5,7 @@ import threading
|
|
5
5
|
import time
|
6
6
|
from tqdm import tqdm
|
7
7
|
from types import FrameType as frame
|
8
|
-
from typing import Callable, Optional, Union
|
8
|
+
from typing import Callable, List, Optional, Union
|
9
9
|
from contextlib import contextmanager
|
10
10
|
from dcicutils.command_utils import yes_or_no
|
11
11
|
|
@@ -54,12 +54,11 @@ class ProgressBar:
|
|
54
54
|
interrupt_exit: bool = False,
|
55
55
|
interrupt_exit_message: Optional[Union[Callable, str]] = None,
|
56
56
|
interrupt_message: Optional[str] = None,
|
57
|
-
|
58
|
-
|
57
|
+
tidy_output_hack: bool = True,
|
58
|
+
capture_output_for_testing: bool = False) -> None:
|
59
59
|
self._bar = None
|
60
60
|
self._disabled = False
|
61
61
|
self._done = False
|
62
|
-
self._printf = printf if callable(printf) else print
|
63
62
|
self._tidy_output_hack = (tidy_output_hack is True)
|
64
63
|
self._started = time.time()
|
65
64
|
self._stop_requested = False
|
@@ -90,7 +89,7 @@ class ProgressBar:
|
|
90
89
|
self._tidy_output_hack = self._define_tidy_output_hack()
|
91
90
|
self._total = total if isinstance(total, int) and total >= 0 else 0
|
92
91
|
self._description = self._format_description(description)
|
93
|
-
|
92
|
+
self._captured_output_for_testing = [] if capture_output_for_testing else None
|
94
93
|
|
95
94
|
def _initialize(self) -> bool:
|
96
95
|
# Do not actually create the tqdm object unless/until we have a positive total.
|
@@ -197,6 +196,10 @@ class ProgressBar:
|
|
197
196
|
def duration(self) -> None:
|
198
197
|
return time.time() - self._started
|
199
198
|
|
199
|
+
@property
|
200
|
+
def captured_output_for_testing(self) -> Optional[List[str]]:
|
201
|
+
return self._captured_output_for_testing
|
202
|
+
|
200
203
|
def _format_description(self, value: str) -> str:
|
201
204
|
if not isinstance(value, str):
|
202
205
|
value = ""
|
@@ -208,8 +211,7 @@ class ProgressBar:
|
|
208
211
|
def handle_interrupt(signum: int, frame: frame) -> None: # noqa
|
209
212
|
nonlocal self
|
210
213
|
def handle_secondary_interrupt(signum: int, frame: frame) -> None: # noqa
|
211
|
-
|
212
|
-
self._printf("\nEnter 'yes' or 'no' or CTRL-\\ to completely abort ...")
|
214
|
+
print("\nEnter 'yes' or 'no' or CTRL-\\ to completely abort ...")
|
213
215
|
self.disable()
|
214
216
|
self._interrupt(self) if self._interrupt else None
|
215
217
|
set_interrupt_handler(handle_secondary_interrupt)
|
@@ -226,7 +228,7 @@ class ProgressBar:
|
|
226
228
|
restore_interrupt_handler()
|
227
229
|
if self._interrupt_exit_message:
|
228
230
|
if isinstance(interrupt_exit_message := self._interrupt_exit_message(self), str):
|
229
|
-
|
231
|
+
print(interrupt_exit_message)
|
230
232
|
exit(1)
|
231
233
|
elif interrupt_stop is False or ((interrupt_stop is None) and (self._interrupt_exit is False)):
|
232
234
|
set_interrupt_handler(handle_interrupt)
|
@@ -257,10 +259,25 @@ class ProgressBar:
|
|
257
259
|
# string in the display string where the progress bar should actually go,
|
258
260
|
# which we do in _format_description. Other minor things too; see below.
|
259
261
|
sys_stdout_write = sys.stdout.write
|
262
|
+
total_most_recent = None
|
263
|
+
progress_most_recent = None
|
264
|
+
description_most_recent = None
|
260
265
|
def tidy_stdout_write(text: str) -> None: # noqa
|
261
266
|
nonlocal self, sys_stdout_write, sentinel_internal, spina, spini, spinn
|
267
|
+
nonlocal total_most_recent, progress_most_recent, description_most_recent
|
262
268
|
def replace_first(value: str, match: str, replacement: str) -> str: # noqa
|
263
269
|
return value[:i] + replacement + value[i + len(match):] if (i := value.find(match)) >= 0 else value
|
270
|
+
def remove_extra_trailing_spaces(text: str) -> str: # noqa
|
271
|
+
while text.endswith(" "):
|
272
|
+
text = text[:-1]
|
273
|
+
return text
|
274
|
+
if not text or not self._bar:
|
275
|
+
return
|
276
|
+
if (self._bar.total == total_most_recent) and (self._bar.n == progress_most_recent):
|
277
|
+
return
|
278
|
+
total_most_recent = self._bar.total
|
279
|
+
progress_most_recent = self._bar.n
|
280
|
+
description_most_recent = self._description
|
264
281
|
if (self._disabled or self._done) and sentinel_internal in text:
|
265
282
|
# Another hack to really disable output on interrupt; in this case we set
|
266
283
|
# tqdm.disable to True, but output can still dribble out, so if the output
|
@@ -270,11 +287,14 @@ class ProgressBar:
|
|
270
287
|
spinc = spina[spini % spinn] if not ("100%|" in text) else "| ✓" ; spini += 1 # noqa
|
271
288
|
text = replace_first(text, sentinel_internal, f" {spinc}")
|
272
289
|
text = replace_first(text, "%|", "% ◀|")
|
290
|
+
text = remove_extra_trailing_spaces(text)
|
273
291
|
# Another oddity: for the rate sometimes tqdm intermittently prints
|
274
292
|
# something like "1.54s/" rather than "1.54/s"; something to do with
|
275
293
|
# the unit we gave, which is empty; idunno; just replace it here.
|
276
294
|
text = replace_first(text, "s/ ", "/s ")
|
277
295
|
sys_stdout_write(text)
|
296
|
+
if self._captured_output_for_testing is not None:
|
297
|
+
self._captured_output_for_testing.append(text)
|
278
298
|
sys.stdout.flush()
|
279
299
|
def restore_stdout_write() -> None: # noqa
|
280
300
|
nonlocal sys_stdout_write
|
dcicutils/structured_data.py
CHANGED
@@ -654,7 +654,9 @@ class Schema(SchemaBase):
|
|
654
654
|
nonlocal self, typeinfo
|
655
655
|
if self._norefs:
|
656
656
|
if value:
|
657
|
-
|
657
|
+
# Dump the src because this cannot add dictionary to a set; note that
|
658
|
+
# this is ONLY used for smaht-submitr/submit-metadata-bundle --info --refs.
|
659
|
+
self._resolved_refs.add((f"/{link_to}/{value}", json.dumps(src) if isinstance(src, dict) else None))
|
658
660
|
return value
|
659
661
|
if not value:
|
660
662
|
if (column := typeinfo.get("column")) and column in self.data.get("required", []):
|
@@ -2,7 +2,7 @@ dcicutils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
2
|
dcicutils/base.py,sha256=gxNEv3DSVUfoX3NToWw7pcCdguxsJ75NDqsPi3wdFG4,5115
|
3
3
|
dcicutils/beanstalk_utils.py,sha256=nHMWfFnZAXFiJh60oVouwbAPMKsQfHnDtkwz_PDE6S4,51434
|
4
4
|
dcicutils/bundle_utils.py,sha256=ZVQcqlt7Yly8-YbL3A-5DW859_hMWpTL6dXtknEYZIw,34669
|
5
|
-
dcicutils/captured_output.py,sha256=
|
5
|
+
dcicutils/captured_output.py,sha256=2pzkq7vtC47zwsSeXS6cJNxC_LXpUbw6ArudKlJHdb0,3108
|
6
6
|
dcicutils/cloudformation_utils.py,sha256=MtWJrSTXyiImgbPHgRvfH9bWso20ZPLTFJAfhDQSVj4,13786
|
7
7
|
dcicutils/codebuild_utils.py,sha256=CKpmhJ-Z8gYbkt1I2zyMlKtFdsg7T8lqrx3V5ieta-U,1155
|
8
8
|
dcicutils/command_utils.py,sha256=JExll5TMqIcmuiGvuS8q4XDUvoEfi2oSH0E2FVF6suU,15285
|
@@ -48,7 +48,7 @@ dcicutils/obfuscation_utils.py,sha256=fo2jOmDRC6xWpYX49u80bVNisqRRoPskFNX3ymFAmj
|
|
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=hEY3YyBHkmGGwyYLzoQ7YGhMcoBATmGt0h64aWHHZTY,14543
|
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
|
@@ -63,7 +63,7 @@ dcicutils/secrets_utils.py,sha256=8dppXAsiHhJzI6NmOcvJV5ldvKkQZzh3Fl-cb8Wm7MI,19
|
|
63
63
|
dcicutils/sheet_utils.py,sha256=VlmzteONW5VF_Q4vo0yA5vesz1ViUah1MZ_yA1rwZ0M,33629
|
64
64
|
dcicutils/snapshot_utils.py,sha256=ymP7PXH6-yEiXAt75w0ldQFciGNqWBClNxC5gfX2FnY,22961
|
65
65
|
dcicutils/ssl_certificate_utils.py,sha256=F0ifz_wnRRN9dfrfsz7aCp4UDLgHEY8LaK7PjnNvrAQ,9707
|
66
|
-
dcicutils/structured_data.py,sha256=
|
66
|
+
dcicutils/structured_data.py,sha256=YCLGtjsCMXCm5ZM96aiTRQ9OPUuj0lK8O9vSkLx1gv8,58450
|
67
67
|
dcicutils/submitr/progress_constants.py,sha256=5bxyX77ql8qEJearfHEvsvXl7D0GuUODW0T65mbRmnE,2895
|
68
68
|
dcicutils/submitr/ref_lookup_strategy.py,sha256=Js2cVznTmgjciLWBPLCvMiwLIHXjDn3jww-gJPjYuFw,3467
|
69
69
|
dcicutils/task_utils.py,sha256=MF8ujmTD6-O2AC2gRGPHyGdUrVKgtr8epT5XU8WtNjk,8082
|
@@ -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.1b3.dist-info/LICENSE.txt,sha256=qnwSmfnEWMl5l78VPDEzAmEbLVrRqQvfUQiHT0ehrOo,1102
|
76
|
+
dcicutils-8.8.3.1b3.dist-info/METADATA,sha256=gphVd0GbW3hvs3vg9d6xDngibRhVMClCQAuOt_3N7Mo,3356
|
77
|
+
dcicutils-8.8.3.1b3.dist-info/WHEEL,sha256=7Z8_27uaHI_UZAc4Uox4PpBhQ9Y5_modZXWMxtUi4NU,88
|
78
|
+
dcicutils-8.8.3.1b3.dist-info/entry_points.txt,sha256=51Q4F_2V10L0282W7HFjP4jdzW4K8lnWDARJQVFy_hw,270
|
79
|
+
dcicutils-8.8.3.1b3.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|