dcicutils 8.8.6.1b11__py3-none-any.whl → 8.8.6.1b13__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.
@@ -1,3 +1,4 @@
1
+ from __future__ import annotations
1
2
  import contextlib
2
3
  import functools
3
4
  import glob
@@ -7,7 +8,7 @@ import re
7
8
  import requests
8
9
  import subprocess
9
10
 
10
- from typing import Optional
11
+ from typing import Callable, Optional
11
12
  from .exceptions import InvalidParameterError
12
13
  from .lang_utils import there_are
13
14
  from .misc_utils import INPUT, PRINT, environ_bool, print_error_message, decorator
@@ -384,3 +385,70 @@ def script_catch_errors():
384
385
  message = str(e) # Note: We ignore the type, which isn't intended to be shown.
385
386
  PRINT(message)
386
387
  exit(1)
388
+
389
+
390
+ class Question:
391
+ """
392
+ Supports asking the user (via stdin) a yes/no question, possibly repeatedly; and after
393
+ some maximum number times of the same answer in a row (consecutively), then asks them
394
+ if they want to automatically give that same answer to any/all subsequent questions.
395
+ Supports static/global list of such Question instances, hashed (only) by the question text.
396
+ """
397
+ _static_instances = {}
398
+
399
+ @staticmethod
400
+ def instance(question: Optional[str] = None,
401
+ max: Optional[int] = None, printf: Optional[Callable] = None) -> Question:
402
+ question = question if isinstance(question, str) else ""
403
+ if not (instance := Question._static_instances.get(question)):
404
+ Question._static_instances[question] = (instance := Question(question, max=max, printf=printf))
405
+ return instance
406
+
407
+ @staticmethod
408
+ def yes(question: Optional[str] = None,
409
+ max: Optional[int] = None, printf: Optional[Callable] = None) -> bool:
410
+ return Question.instance(question, max=max, printf=printf).ask()
411
+
412
+ def __init__(self, question: Optional[str] = None,
413
+ max: Optional[int] = None, printf: Optional[Callable] = None) -> None:
414
+ self._question = question if isinstance(question, str) else ""
415
+ self._max = max if isinstance(max, int) and max > 0 else None
416
+ self._print = printf if callable(printf) else print
417
+ self._yes_consecutive_count = 0
418
+ self._no_consecutive_count = 0
419
+ self._yes_automatic = False
420
+ self._no_automatic = False
421
+
422
+ def ask(self, question: Optional[str] = None) -> bool:
423
+
424
+ def question_automatic(value: str) -> bool:
425
+ nonlocal self
426
+ RARROW = "▶"
427
+ LARROW = "◀"
428
+ if yes_or_no(f"{RARROW}{RARROW}{RARROW}"
429
+ f" Do you want to answer {value} to all such questions?"
430
+ f" {LARROW}{LARROW}{LARROW}"):
431
+ return True
432
+ self._yes_consecutive_count = 0
433
+ self._no_consecutive_count = 0
434
+
435
+ if self._yes_automatic:
436
+ return True
437
+ elif self._no_automatic:
438
+ return False
439
+ elif yes_or_no((question if isinstance(question, str) else "") or self._question or "Undefined question"):
440
+ self._yes_consecutive_count += 1
441
+ self._no_consecutive_count = 0
442
+ if (self._no_consecutive_count == 0) and self._max and (self._yes_consecutive_count >= self._max):
443
+ # Have reached the maximum number of consecutive YES answers; ask if YES to all subsequent.
444
+ if question_automatic("YES"):
445
+ self._yes_automatic = True
446
+ return True
447
+ else:
448
+ self._no_consecutive_count += 1
449
+ self._yes_consecutive_count = 0
450
+ if (self._yes_consecutive_count == 0) and self._max and (self._no_consecutive_count >= self._max):
451
+ # Have reached the maximum number of consecutive NO answers; ask if NO to all subsequent.
452
+ if question_automatic("NO"):
453
+ self._no_automatic = True
454
+ return False
@@ -11,7 +11,6 @@ from webtest.app import TestApp
11
11
  from dcicutils.common import OrchestratedApp
12
12
  from dcicutils.data_readers import CsvReader, Excel, RowReader
13
13
  from dcicutils.datetime_utils import normalize_date_string, normalize_datetime_string
14
- from dcicutils.file_utils import search_for_file
15
14
  from dcicutils.misc_utils import (create_dict, create_readonly_object, is_uuid, load_json_if,
16
15
  merge_objects, remove_empty_properties, right_trim, split_string,
17
16
  to_boolean, to_enum, to_float, to_integer, VirtualApp)
@@ -209,14 +208,6 @@ class StructuredDataSet:
209
208
  result.append({"type": type_name, "file": file_name})
210
209
  return result
211
210
 
212
- def upload_files_located(self,
213
- location: Union[str, Optional[List[str]]] = None, recursive: bool = False) -> List[str]:
214
- upload_files = copy.deepcopy(self.upload_files)
215
- for upload_file in upload_files:
216
- if file_path := search_for_file(upload_file["file"], location, recursive=recursive, single=True):
217
- upload_file["path"] = file_path
218
- return upload_files
219
-
220
211
  @property
221
212
  def nrows(self) -> int:
222
213
  return self._nrows
@@ -351,20 +342,22 @@ class StructuredDataSet:
351
342
 
352
343
  def _load_json_file(self, file: str) -> None:
353
344
  with open(file) as f:
354
- item = json.load(f)
345
+ data = json.load(f)
346
+ import pdb ; pdb.set_trace() # noqa
347
+ pass
355
348
  if ((schema_name_inferred_from_file_name := Schema.type_name(file)) and
356
349
  (self._portal.get_schema(schema_name_inferred_from_file_name) is not None)): # noqa
357
350
  # If the JSON file name looks like a schema name then assume it
358
351
  # contains an object or an array of object of that schema type.
359
352
  if self._merge:
360
- item = self._merge_with_existing_portal_object(item, schema_name_inferred_from_file_name)
361
- self._add(Schema.type_name(file), item)
362
- elif isinstance(item, dict):
353
+ data = self._merge_with_existing_portal_object(data, schema_name_inferred_from_file_name)
354
+ self._add(Schema.type_name(file), data)
355
+ elif isinstance(data, dict):
363
356
  # Otherwise if the JSON file name does not look like a schema name then
364
357
  # assume it a dictionary where each property is the name of a schema, and
365
358
  # which (each property) contains a list of object of that schema type.
366
- for schema_name in item:
367
- item = item[schema_name]
359
+ for schema_name in data:
360
+ item = data[schema_name]
368
361
  if self._merge:
369
362
  item = self._merge_with_existing_portal_object(item, schema_name)
370
363
  self._add(schema_name, item)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dcicutils
3
- Version: 8.8.6.1b11
3
+ Version: 8.8.6.1b13
4
4
  Summary: Utility package for interacting with the 4DN Data Portal and other 4DN resources
5
5
  Home-page: https://github.com/4dn-dcic/utils
6
6
  License: MIT
@@ -5,7 +5,7 @@ dcicutils/bundle_utils.py,sha256=ZVQcqlt7Yly8-YbL3A-5DW859_hMWpTL6dXtknEYZIw,346
5
5
  dcicutils/captured_output.py,sha256=0hP7sPwleMaYXQAvCfJOxG8Z8T_JJYy8ADp8A5ZoblE,3295
6
6
  dcicutils/cloudformation_utils.py,sha256=MtWJrSTXyiImgbPHgRvfH9bWso20ZPLTFJAfhDQSVj4,13786
7
7
  dcicutils/codebuild_utils.py,sha256=CKpmhJ-Z8gYbkt1I2zyMlKtFdsg7T8lqrx3V5ieta-U,1155
8
- dcicutils/command_utils.py,sha256=JExll5TMqIcmuiGvuS8q4XDUvoEfi2oSH0E2FVF6suU,15285
8
+ dcicutils/command_utils.py,sha256=1_h18LGX86sLAkRkH33HNmBkwMb7v2wAh3jL01hzceU,18487
9
9
  dcicutils/common.py,sha256=YE8Mt5-vaZWWz4uaChSVhqGFbFtW5QKtnIyOr4zG4vM,3955
10
10
  dcicutils/contribution_scripts.py,sha256=0k5Gw1TumcD5SAcXVkDd6-yvuMEw-jUp5Kfb7FJH6XQ,2015
11
11
  dcicutils/contribution_utils.py,sha256=vYLS1JUB3sKd24BUxZ29qUBqYeQBLK9cwo8x3k64uPg,25653
@@ -64,7 +64,7 @@ dcicutils/secrets_utils.py,sha256=8dppXAsiHhJzI6NmOcvJV5ldvKkQZzh3Fl-cb8Wm7MI,19
64
64
  dcicutils/sheet_utils.py,sha256=VlmzteONW5VF_Q4vo0yA5vesz1ViUah1MZ_yA1rwZ0M,33629
65
65
  dcicutils/snapshot_utils.py,sha256=ymP7PXH6-yEiXAt75w0ldQFciGNqWBClNxC5gfX2FnY,22961
66
66
  dcicutils/ssl_certificate_utils.py,sha256=F0ifz_wnRRN9dfrfsz7aCp4UDLgHEY8LaK7PjnNvrAQ,9707
67
- dcicutils/structured_data.py,sha256=sm8x08ckPZcIcyBaSlQRGrOD3YL9d09gz-xB3_TAWGE,64516
67
+ dcicutils/structured_data.py,sha256=KxwDJ9wwEnT7NCsEw9bKrufGYe2wfP2Zoy8zipTk0Gs,64096
68
68
  dcicutils/submitr/progress_constants.py,sha256=5bxyX77ql8qEJearfHEvsvXl7D0GuUODW0T65mbRmnE,2895
69
69
  dcicutils/submitr/ref_lookup_strategy.py,sha256=VJN-Oo0LLna6Vo2cu47eC-eU-yUC9NFlQP29xajejVU,4741
70
70
  dcicutils/task_utils.py,sha256=MF8ujmTD6-O2AC2gRGPHyGdUrVKgtr8epT5XU8WtNjk,8082
@@ -73,8 +73,8 @@ dcicutils/trace_utils.py,sha256=g8kwV4ebEy5kXW6oOrEAUsurBcCROvwtZqz9fczsGRE,1769
73
73
  dcicutils/validation_utils.py,sha256=cMZIU2cY98FYtzK52z5WUYck7urH6JcqOuz9jkXpqzg,14797
74
74
  dcicutils/variant_utils.py,sha256=2H9azNx3xAj-MySg-uZ2SFqbWs4kZvf61JnK6b-h4Qw,4343
75
75
  dcicutils/zip_utils.py,sha256=_Y9EmL3D2dUZhxucxHvrtmmlbZmK4FpSsHEb7rGSJLU,3265
76
- dcicutils-8.8.6.1b11.dist-info/LICENSE.txt,sha256=qnwSmfnEWMl5l78VPDEzAmEbLVrRqQvfUQiHT0ehrOo,1102
77
- dcicutils-8.8.6.1b11.dist-info/METADATA,sha256=VlpuTBAxKkqXFztHeEfDLxXP_BBRVBbpjmQoaEjGuJo,3440
78
- dcicutils-8.8.6.1b11.dist-info/WHEEL,sha256=7Z8_27uaHI_UZAc4Uox4PpBhQ9Y5_modZXWMxtUi4NU,88
79
- dcicutils-8.8.6.1b11.dist-info/entry_points.txt,sha256=51Q4F_2V10L0282W7HFjP4jdzW4K8lnWDARJQVFy_hw,270
80
- dcicutils-8.8.6.1b11.dist-info/RECORD,,
76
+ dcicutils-8.8.6.1b13.dist-info/LICENSE.txt,sha256=qnwSmfnEWMl5l78VPDEzAmEbLVrRqQvfUQiHT0ehrOo,1102
77
+ dcicutils-8.8.6.1b13.dist-info/METADATA,sha256=u0aE7aX6k854ZrCide1x5MCfmaqMi2dc4JUx6ZnYA5M,3440
78
+ dcicutils-8.8.6.1b13.dist-info/WHEEL,sha256=7Z8_27uaHI_UZAc4Uox4PpBhQ9Y5_modZXWMxtUi4NU,88
79
+ dcicutils-8.8.6.1b13.dist-info/entry_points.txt,sha256=51Q4F_2V10L0282W7HFjP4jdzW4K8lnWDARJQVFy_hw,270
80
+ dcicutils-8.8.6.1b13.dist-info/RECORD,,