dcicutils 8.8.3.1b5__py3-none-any.whl → 8.8.3.1b8__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/progress_bar.py +39 -27
- dcicutils/structured_data.py +33 -4
- {dcicutils-8.8.3.1b5.dist-info → dcicutils-8.8.3.1b8.dist-info}/METADATA +1 -1
- {dcicutils-8.8.3.1b5.dist-info → dcicutils-8.8.3.1b8.dist-info}/RECORD +7 -7
- {dcicutils-8.8.3.1b5.dist-info → dcicutils-8.8.3.1b8.dist-info}/LICENSE.txt +0 -0
- {dcicutils-8.8.3.1b5.dist-info → dcicutils-8.8.3.1b8.dist-info}/WHEEL +0 -0
- {dcicutils-8.8.3.1b5.dist-info → dcicutils-8.8.3.1b8.dist-info}/entry_points.txt +0 -0
dcicutils/progress_bar.py
CHANGED
@@ -61,6 +61,8 @@ class ProgressBar:
|
|
61
61
|
self._bar = None
|
62
62
|
self._disabled = False
|
63
63
|
self._done = False
|
64
|
+
self._really_done = False
|
65
|
+
self.foo = time.time()
|
64
66
|
self._tidy_output_hack = (tidy_output_hack is True)
|
65
67
|
self._started = time.time()
|
66
68
|
self._stop_requested = False
|
@@ -104,11 +106,9 @@ class ProgressBar:
|
|
104
106
|
return True
|
105
107
|
return False
|
106
108
|
|
107
|
-
def set_total(self, value: int
|
109
|
+
def set_total(self, value: int) -> None:
|
108
110
|
if value == self._total:
|
109
111
|
# If the total has not changed since last set then do nothing.
|
110
|
-
if reset_eta and self._bar is not None:
|
111
|
-
self._bar.reset()
|
112
112
|
return
|
113
113
|
if isinstance(value, int) and value > 0:
|
114
114
|
self._total = value
|
@@ -119,16 +119,6 @@ class ProgressBar:
|
|
119
119
|
self._bar.total = value
|
120
120
|
self._bar.refresh()
|
121
121
|
|
122
|
-
def reset_eta(self) -> None:
|
123
|
-
# Since set_total does nothing if total is the same, provide
|
124
|
-
# a way to reset the ETA if starting over with the same total.
|
125
|
-
if self._bar is not None:
|
126
|
-
progress = self._bar.n
|
127
|
-
self._bar.reset()
|
128
|
-
self._bar.total = self._total
|
129
|
-
self._bar.n = progress
|
130
|
-
self._bar.refresh()
|
131
|
-
|
132
122
|
def set_progress(self, value: int) -> None:
|
133
123
|
if isinstance(value, int) and value >= 0:
|
134
124
|
if (self._bar is not None) or self._initialize():
|
@@ -141,17 +131,29 @@ class ProgressBar:
|
|
141
131
|
self._bar.update(value)
|
142
132
|
self._bar.refresh()
|
143
133
|
|
144
|
-
def
|
145
|
-
|
134
|
+
def reset_eta(self) -> None:
|
135
|
+
# Since set_total does nothing if total is the same, provide
|
136
|
+
# a way to reset the ETA if starting over with the same total.
|
137
|
+
# But NOTE that resetting ETA will ALSO reset the ELAPSED time.
|
146
138
|
if self._bar is not None:
|
147
|
-
self._bar.
|
139
|
+
progress = self._bar.n
|
140
|
+
self._bar.reset()
|
141
|
+
self._bar.total = self._total
|
142
|
+
self._bar.n = progress
|
143
|
+
self._bar.refresh()
|
148
144
|
|
149
|
-
def
|
145
|
+
def set_description(self, value: str) -> None:
|
146
|
+
if isinstance(value, str):
|
147
|
+
self._description = self._format_description(value)
|
148
|
+
if self._bar is not None:
|
149
|
+
self._bar.set_description(self._description)
|
150
|
+
|
151
|
+
def done(self, description: Optional[str] = None) -> None:
|
150
152
|
if self._done or self._bar is None:
|
151
153
|
return
|
152
154
|
self._ended = time.time()
|
153
155
|
self.set_progress(self.total)
|
154
|
-
self.
|
156
|
+
self.set_description(description)
|
155
157
|
self._bar.refresh()
|
156
158
|
# FYI: Do NOT do a bar.disable = True before a bar.close() or it messes up output
|
157
159
|
# on multiple calls; found out the hard way; a couple hours will never get back :-/
|
@@ -202,6 +204,12 @@ class ProgressBar:
|
|
202
204
|
def captured_output_for_testing(self) -> Optional[List[str]]:
|
203
205
|
return self._captured_output_for_testing
|
204
206
|
|
207
|
+
@staticmethod
|
208
|
+
def format_captured_output_for_testing(description: str, total: int, progress: int) -> str:
|
209
|
+
percent = round((progress / total) * 100.0)
|
210
|
+
separator = "✓" if percent == 100 else "|"
|
211
|
+
return f"{description} {separator} {percent:>3}% ◀|### | {progress}/{total} | 0.0/s | 00:00 | ETA: 00:00"
|
212
|
+
|
205
213
|
def _format_description(self, value: str) -> str:
|
206
214
|
if not isinstance(value, str):
|
207
215
|
value = ""
|
@@ -261,22 +269,19 @@ class ProgressBar:
|
|
261
269
|
# string in the display string where the progress bar should actually go,
|
262
270
|
# which we do in _format_description. Other minor things too; see below.
|
263
271
|
sys_stdout_write = sys.stdout.write
|
264
|
-
|
272
|
+
last_text = None ; last_captured_output_text = None # noqa
|
265
273
|
def tidy_stdout_write(text: str) -> None: # noqa
|
266
274
|
nonlocal self, sys_stdout_write, sentinel_internal, spina, spini, spinn
|
267
|
-
nonlocal
|
275
|
+
nonlocal last_text, last_captured_output_text
|
268
276
|
def replace_first(value: str, match: str, replacement: str) -> str: # noqa
|
269
277
|
return value[:i] + replacement + value[i + len(match):] if (i := value.find(match)) >= 0 else value
|
270
278
|
def remove_extra_trailing_spaces(text: str) -> str: # noqa
|
271
279
|
while text.endswith(" "):
|
272
280
|
text = text[:-1]
|
273
281
|
return text
|
274
|
-
if not text:
|
282
|
+
if (not text) or (last_text == text) or self._really_done:
|
275
283
|
return
|
276
|
-
|
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
|
284
|
+
last_text = text
|
280
285
|
if (self._disabled or self._done) and sentinel_internal in text:
|
281
286
|
# Another hack to really disable output on interrupt; in this case we set
|
282
287
|
# tqdm.disable to True, but output can still dribble out, so if the output
|
@@ -293,6 +298,9 @@ class ProgressBar:
|
|
293
298
|
text = replace_first(text, "s/ ", "/s ")
|
294
299
|
sys_stdout_write(text)
|
295
300
|
sys.stdout.flush()
|
301
|
+
if self._done:
|
302
|
+
self._really_done = True
|
303
|
+
return
|
296
304
|
if self._captured_output_for_testing is not None:
|
297
305
|
# For testing only we replace vacilliting values in the out like rate,
|
298
306
|
# time elapsed, and ETA with static values; so that something like this:
|
@@ -300,7 +308,7 @@ class ProgressBar:
|
|
300
308
|
# becomes something more static like this after calling this function:
|
301
309
|
# > Working | 20% ◀|### | 1/5 | 0.0/s | 00:00 | ETA: 00:00
|
302
310
|
# This function obviously has intimate knowledge of the output; better here than in tests.
|
303
|
-
def
|
311
|
+
def replace_time_dependent_values_with_static(text: str) -> str:
|
304
312
|
blocks = "\u2587|\u2588|\u2589|\u258a|\u258b|\u258c|\u258d|\u258e|\u258f"
|
305
313
|
if (n := find_nth_from_end(text, "|", 5)) >= 8:
|
306
314
|
pattern = re.compile(
|
@@ -311,7 +319,11 @@ class ProgressBar:
|
|
311
319
|
return (text[0:n - 6].replace("\r", "") +
|
312
320
|
match.expand(rf"\g<1>\g<2>### \g<3>\g<4>0.0\g<5>00:00\g<6>00:00"))
|
313
321
|
return text
|
314
|
-
|
322
|
+
if text != "\n":
|
323
|
+
captured_output_text = replace_time_dependent_values_with_static(text)
|
324
|
+
if captured_output_text != last_captured_output_text:
|
325
|
+
self._captured_output_for_testing.append(captured_output_text)
|
326
|
+
last_captured_output_text = captured_output_text
|
315
327
|
def restore_stdout_write() -> None: # noqa
|
316
328
|
nonlocal sys_stdout_write
|
317
329
|
if sys_stdout_write is not None:
|
dcicutils/structured_data.py
CHANGED
@@ -154,7 +154,32 @@ class StructuredDataSet:
|
|
154
154
|
|
155
155
|
@property
|
156
156
|
def resolved_refs_with_uuids(self) -> List[str]:
|
157
|
-
return list([{"path": resolved_ref[0],
|
157
|
+
return list([{"path": resolved_ref[0],
|
158
|
+
"uuid": resolved_ref[1] if len(resolved_ref) >= 2 else None}
|
159
|
+
for resolved_ref in self._resolved_refs])
|
160
|
+
|
161
|
+
@property
|
162
|
+
def unchecked_refs(self) -> List[str]:
|
163
|
+
"""
|
164
|
+
Returns list of unchecked (for existence) references, grouped by reference path;
|
165
|
+
each object in the list has a path property and a srcs property which is a list of
|
166
|
+
src objects containing the type, column and row of the reference to the reference.
|
167
|
+
Note that this is only populated if the norefs option is specified.
|
168
|
+
"""
|
169
|
+
def load_json(value: str) -> Optional[dict]:
|
170
|
+
try:
|
171
|
+
return json.loads(value)
|
172
|
+
except Exception:
|
173
|
+
return None
|
174
|
+
result = []
|
175
|
+
if self._norefs:
|
176
|
+
for ref in self._resolved_refs:
|
177
|
+
if len(ref) >= 3 and (ref_path := ref[0]) and (ref_src := load_json(ref[2])):
|
178
|
+
if existing_ref := [item for item in result if item.get("path") == ref_path]:
|
179
|
+
existing_ref[0]["srcs"].append(ref_src)
|
180
|
+
else:
|
181
|
+
result.append({"path": ref_path, "srcs": [ref_src]})
|
182
|
+
return result
|
158
183
|
|
159
184
|
@property
|
160
185
|
def upload_files(self) -> List[str]:
|
@@ -653,10 +678,14 @@ class Schema(SchemaBase):
|
|
653
678
|
def map_ref(value: str, link_to: str, portal: Optional[Portal], src: Optional[str]) -> Any:
|
654
679
|
nonlocal self, typeinfo
|
655
680
|
if self._norefs:
|
681
|
+
# Here the caller has specified the (StructuredDataSet) norefs option
|
682
|
+
# which means we do not check for the existence of references at all.
|
656
683
|
if value:
|
657
|
-
# Dump the src because
|
658
|
-
# this is ONLY used for smaht-submitr/submit-metadata-bundle --info --refs.
|
659
|
-
|
684
|
+
# Dump the src as a JSON string because a dictionary cannot be added to a set; note
|
685
|
+
# that this is ONLY used for smaht-submitr/submit-metadata-bundle --info --refs.
|
686
|
+
# This info can be gotten at using StructureDataSet.unchecked_refs.
|
687
|
+
self._resolved_refs.add((f"/{link_to}/{value}", None,
|
688
|
+
json.dumps(src) if isinstance(src, dict) else None))
|
660
689
|
return value
|
661
690
|
if not value:
|
662
691
|
if (column := typeinfo.get("column")) and column in self.data.get("required", []):
|
@@ -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=j6dZdh5EeZo52GWIBu2JL5254-V6eOhKHHB2eCkgevI,16569
|
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=Ho97KAqPgfn9QVfIMpjp0gS1FXLAnEJu6usdVi2lGHc,59927
|
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.1b8.dist-info/LICENSE.txt,sha256=qnwSmfnEWMl5l78VPDEzAmEbLVrRqQvfUQiHT0ehrOo,1102
|
76
|
+
dcicutils-8.8.3.1b8.dist-info/METADATA,sha256=saFsKdu4mbE4RBPh2331yy2nC-ZUcE5n3fT740wn9iY,3356
|
77
|
+
dcicutils-8.8.3.1b8.dist-info/WHEEL,sha256=7Z8_27uaHI_UZAc4Uox4PpBhQ9Y5_modZXWMxtUi4NU,88
|
78
|
+
dcicutils-8.8.3.1b8.dist-info/entry_points.txt,sha256=51Q4F_2V10L0282W7HFjP4jdzW4K8lnWDARJQVFy_hw,270
|
79
|
+
dcicutils-8.8.3.1b8.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|