dcicutils 8.5.0.1b4__py3-none-any.whl → 8.6.0.0b0__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
dcicutils/misc_utils.py CHANGED
@@ -982,11 +982,7 @@ def to_integer(value: str, fallback: Optional[Any] = None) -> Optional[Any]:
982
982
  try:
983
983
  return int(value)
984
984
  except Exception:
985
- try:
986
- return int(float(value))
987
- except Exception:
988
- pass
989
- return fallback
985
+ return fallback
990
986
 
991
987
 
992
988
  def to_float(value: str, fallback: Optional[Any] = None) -> Optional[Any]:
@@ -1469,33 +1465,28 @@ def string_list(s):
1469
1465
  return [p for p in [part.strip() for part in s.split(",")] if p]
1470
1466
 
1471
1467
 
1472
- def split_string(value: str, delimiter: str, escape: Optional[str] = None, unique: bool = False) -> List[str]:
1468
+ def split_string(value: str, delimiter: str, escape: Optional[str] = None) -> List[str]:
1473
1469
  """
1474
1470
  Splits the given string into an array of string based on the given delimiter, and an optional escape character.
1475
1471
  """
1476
1472
  if not isinstance(value, str) or not (value := value.strip()):
1477
1473
  return []
1478
- result = []
1479
1474
  if not isinstance(escape, str) or not escape:
1480
- for item in value.split(delimiter):
1481
- if (item := item.strip()) and (unique is not True or item not in result):
1482
- result.append(item)
1483
- return result
1475
+ return [item.strip() for item in value.split(delimiter)]
1476
+ result = []
1484
1477
  item = r""
1485
1478
  escaped = False
1486
1479
  for c in value:
1487
1480
  if c == delimiter and not escaped:
1488
- if (item := item.strip()) and (unique is not True or item not in result):
1489
- result.append(item)
1481
+ result.append(item.strip())
1490
1482
  item = r""
1491
1483
  elif c == escape and not escaped:
1492
1484
  escaped = True
1493
1485
  else:
1494
1486
  item += c
1495
1487
  escaped = False
1496
- if (item := item.strip()) and (unique is not True or item not in result):
1497
- result.append(item)
1498
- return result
1488
+ result.append(item.strip())
1489
+ return [item for item in result if item]
1499
1490
 
1500
1491
 
1501
1492
  def right_trim(list_or_tuple: Union[List[Any], Tuple[Any]],
dcicutils/portal_utils.py CHANGED
@@ -23,14 +23,15 @@ class Portal:
23
23
  2. From a key dictionary, containing "key" and "secret" property values.
24
24
  3. From a key tuple, containing (in order) a key and secret values.
25
25
  4. From a keys file assumed to reside in ~/.{app}-keys.json where the given "app" value is either "smaht", "cgap",
26
- or "fourfront"; where is assumed to contain a dictionary with a key for the given "env" value, e.g. smaht-local;
27
- and with a dictionary value containing "key" and "secret" property values, and an optional "server" property;
28
- if an "app" value is not specified but the given "env" value begins with one of the app values then that value
29
- will be used, i.e. e.g. if "env" is "smaht-local" and app is unspecified than it is assumed to be "smaht".
26
+ or "fourfront"; and where this file is assumed to contain a dictionary with a key equal to the given "env"
27
+ value (e.g. smaht-localhost) and with a dictionary value containing "key" and "secret" property values; if
28
+ an "app" value is not specified but the given "env" value begins with one of the app values then that value
29
+ will be used, i.e. e.g. if env is "smaht-localhost" and app is unspecified than it is assumed to be "smaht".
30
30
  5. From a keys file as described above (#4) but rather than be identified by the given "env" value it
31
- is looked up via the given "server" name and the "server" key dictionary value in the key file.
31
+ is looked up by the given "server" name and the "server" key dictionary value in the key file.
32
32
  6. From a given "vapp" value (which is assumed to be a TestApp or VirtualApp).
33
- 7. From another Portal object; or from a a pyramid Router object.
33
+ 7. From another Portal object.
34
+ 8. From a a pyramid Router object.
34
35
  """
35
36
  def __init__(self,
36
37
  arg: Optional[Union[VirtualApp, TestApp, Router, Portal, dict, tuple, str]] = None,
@@ -61,7 +62,6 @@ class Portal:
61
62
  self._server = portal._server
62
63
  self._key = portal._key
63
64
  self._key_pair = portal._key_pair
64
- self._key_id = portal._key_id
65
65
  self._key_file = portal._key_file
66
66
  return
67
67
  self._vapp = None
@@ -70,7 +70,6 @@ class Portal:
70
70
  self._server = server
71
71
  self._key = None
72
72
  self._key_pair = None
73
- self._key_id = None
74
73
  self._key_file = None
75
74
  if isinstance(portal, (VirtualApp, TestApp)):
76
75
  self._vapp = portal
@@ -96,10 +95,6 @@ class Portal:
96
95
  self._key = key_manager.get_keydict_for_server(self._server)
97
96
  self._key_pair = key_manager.keydict_to_keypair(self._key) if self._key else None
98
97
  self._key_file = key_manager.keys_file
99
- if self._key and (key_id := self._key.get("key")):
100
- self._key_id = key_id
101
- elif self._key_pair and (key_id := self._key_pair[1]):
102
- self._key_id = key_id
103
98
 
104
99
  @property
105
100
  def env(self):
@@ -121,10 +116,6 @@ class Portal:
121
116
  def key_pair(self):
122
117
  return self._key_pair
123
118
 
124
- @property
125
- def key_id(self):
126
- return self._key_id
127
-
128
119
  @property
129
120
  def key_file(self):
130
121
  return self._key_file
@@ -215,19 +206,13 @@ class Portal:
215
206
  super_type_map_flattened[super_type_name] = breadth_first(super_type_map, super_type_name)
216
207
  return super_type_map_flattened
217
208
 
218
- def ping(self) -> bool:
219
- try:
220
- return self.get("/health").status_code == 200
221
- except Exception:
222
- return False
223
-
224
209
  def _uri(self, uri: str) -> str:
225
210
  if not isinstance(uri, str) or not uri:
226
211
  return "/"
227
212
  if uri.lower().startswith("http://") or uri.lower().startswith("https://"):
228
213
  return uri
229
214
  uri = re.sub(r"/+", "/", uri)
230
- return (self._server + ("/" if not uri.startswith("/") else "") + uri) if self._server else uri
215
+ return (self._server + ("/" if uri.startswith("/") else "") + uri) if self._server else uri
231
216
 
232
217
  def _kwargs(self, **kwargs) -> dict:
233
218
  result_kwargs = {"headers":
@@ -0,0 +1,142 @@
1
+ from typing import Any, Dict, List
2
+
3
+
4
+ class JsonSchemaConstants:
5
+ ANY_OF = "anyOf"
6
+ ARRAY = "array"
7
+ BOOLEAN = "boolean"
8
+ ENUM = "enum"
9
+ INTEGER = "integer"
10
+ ITEMS = "items"
11
+ NUMBER = "number"
12
+ OBJECT = "object"
13
+ ONE_OF = "oneOf"
14
+ PATTERN = "pattern"
15
+ PROPERTIES = "properties"
16
+ REQUIRED = "required"
17
+ STRING = "string"
18
+ TYPE = "type"
19
+
20
+
21
+ class EncodedSchemaConstants:
22
+ DEFAULT = "default"
23
+ FORMAT = "format"
24
+ IDENTIFYING_PROPERTIES = "identifyingProperties"
25
+ LINK_TO = "linkTo"
26
+ MERGE_REF = "$merge"
27
+ MIXIN_PROPERTIES = "mixinProperties"
28
+ REF = "$ref"
29
+ UNIQUE_KEY = "uniqueKey"
30
+
31
+
32
+ class SchemaConstants(JsonSchemaConstants, EncodedSchemaConstants):
33
+ pass
34
+
35
+
36
+ def get_properties(schema: Dict[str, Any]) -> Dict[str, Any]:
37
+ """Return the properties of a schema."""
38
+ return schema.get(SchemaConstants.PROPERTIES, {})
39
+
40
+
41
+ def get_required(schema: Dict[str, Any]) -> List[str]:
42
+ """Return the required properties of a schema."""
43
+ return schema.get(SchemaConstants.REQUIRED, [])
44
+
45
+
46
+ def get_any_of(schema: Dict[str, Any]) -> List[Dict[str, Any]]:
47
+ """Return the anyOf properties of a schema."""
48
+ return schema.get(SchemaConstants.ANY_OF, [])
49
+
50
+
51
+ def get_one_of(schema: Dict[str, Any]) -> List[Dict[str, Any]]:
52
+ """Return the oneOf properties of a schema."""
53
+ return schema.get(SchemaConstants.ONE_OF, [])
54
+
55
+
56
+ def get_conditionally_required_properties(schema: Dict[str, Any]) -> List[str]:
57
+ """Get required + possibly required properties.
58
+
59
+ Using heuristics here; update as needed.
60
+ """
61
+ return sorted(
62
+ list(
63
+ set(
64
+ get_required(schema)
65
+ + get_any_of_required_properties(schema)
66
+ + get_one_of_required_properties(schema)
67
+ )
68
+ )
69
+ )
70
+
71
+
72
+ def get_any_of_required_properties(schema: Dict[str, Any]) -> List[str]:
73
+ """Get required properties from anyOf."""
74
+ return [
75
+ property_name
76
+ for any_of_schema in get_any_of(schema)
77
+ for property_name in get_required(any_of_schema)
78
+ ]
79
+
80
+
81
+ def get_one_of_required_properties(schema: Dict[str, Any]) -> List[str]:
82
+ """Get required properties from oneOf."""
83
+ return [
84
+ property_name
85
+ for one_of_schema in get_one_of(schema)
86
+ for property_name in get_required(one_of_schema)
87
+ ]
88
+
89
+
90
+ def get_mixin_properties(schema: Dict[str, Any]) -> List[Dict[str, Any]]:
91
+ """Return the mixin properties of a schema."""
92
+ return schema.get(EncodedSchemaConstants.MIXIN_PROPERTIES, [])
93
+
94
+
95
+ def get_identifying_properties(schema: Dict[str, Any]) -> List[str]:
96
+ """Return the identifying properties of a schema."""
97
+ return schema.get(EncodedSchemaConstants.IDENTIFYING_PROPERTIES, [])
98
+
99
+
100
+ def get_schema_type(schema: Dict[str, Any]) -> str:
101
+ """Return the type of a schema."""
102
+ return schema.get(SchemaConstants.TYPE, "")
103
+
104
+
105
+ def is_array_schema(schema: Dict[str, Any]) -> bool:
106
+ """Return True if the schema is an array."""
107
+ return get_schema_type(schema) == SchemaConstants.ARRAY
108
+
109
+
110
+ def is_object_schema(schema: Dict[str, Any]) -> bool:
111
+ """Return True if the schema is an object."""
112
+ return get_schema_type(schema) == SchemaConstants.OBJECT
113
+
114
+
115
+ def is_string_schema(schema: Dict[str, Any]) -> bool:
116
+ """Return True if the schema is a string."""
117
+ return get_schema_type(schema) == SchemaConstants.STRING
118
+
119
+
120
+ def is_number_schema(schema: Dict[str, Any]) -> bool:
121
+ """Return True if the schema is a number."""
122
+ return get_schema_type(schema) == SchemaConstants.NUMBER
123
+
124
+
125
+ def is_integer_schema(schema: Dict[str, Any]) -> bool:
126
+ """Return True if the schema is an integer."""
127
+ return get_schema_type(schema) == SchemaConstants.INTEGER
128
+
129
+
130
+ def is_boolean_schema(schema: Dict[str, Any]) -> bool:
131
+ """Return True if the schema is a boolean."""
132
+ return get_schema_type(schema) == SchemaConstants.BOOLEAN
133
+
134
+
135
+ def get_items(schema: Dict[str, Any]) -> Dict[str, Any]:
136
+ """Return the items of a schema."""
137
+ return schema.get(SchemaConstants.ITEMS, {})
138
+
139
+
140
+ def has_property(schema: Dict[str, Any], property_name: str) -> bool:
141
+ """Return True if the schema has the given property."""
142
+ return property_name in get_properties(schema)
@@ -42,24 +42,23 @@ StructuredDataSet = Type["StructuredDataSet"]
42
42
  class StructuredDataSet:
43
43
 
44
44
  def __init__(self, file: Optional[str] = None, portal: Optional[Union[VirtualApp, TestApp, Portal]] = None,
45
- schemas: Optional[List[dict]] = None, autoadd: Optional[dict] = None,
46
- data: Optional[List[dict]] = None, order: Optional[List[str]] = None, prune: bool = True) -> None:
45
+ schemas: Optional[List[dict]] = None, data: Optional[List[dict]] = None,
46
+ order: Optional[List[str]] = None, prune: bool = True) -> None:
47
47
  self.data = {} if not data else data # If portal is None then no schemas nor refs.
48
48
  self._portal = Portal(portal, data=self.data, schemas=schemas) if portal else None
49
49
  self._order = order
50
50
  self._prune = prune
51
51
  self._warnings = {}
52
52
  self._errors = {}
53
- self._resolved_refs = set()
53
+ self._resolved_refs = []
54
54
  self._validated = False
55
- self._autoadd_properties = autoadd if isinstance(autoadd, dict) and autoadd else None
56
55
  self._load_file(file) if file else None
57
56
 
58
57
  @staticmethod
59
58
  def load(file: str, portal: Optional[Union[VirtualApp, TestApp, Portal]] = None,
60
- schemas: Optional[List[dict]] = None, autoadd: Optional[dict] = None,
59
+ schemas: Optional[List[dict]] = None,
61
60
  order: Optional[List[str]] = None, prune: bool = True) -> StructuredDataSet:
62
- return StructuredDataSet(file=file, portal=portal, schemas=schemas, autoadd=autoadd, order=order, prune=prune)
61
+ return StructuredDataSet(file=file, portal=portal, schemas=schemas, order=order, prune=prune)
63
62
 
64
63
  def validate(self, force: bool = False) -> None:
65
64
  if self._validated and not force:
@@ -97,7 +96,7 @@ class StructuredDataSet:
97
96
 
98
97
  @property
99
98
  def resolved_refs(self) -> List[str]:
100
- return list(self._resolved_refs)
99
+ return self._resolved_refs
101
100
 
102
101
  @property
103
102
  def upload_files(self) -> List[str]:
@@ -164,13 +163,11 @@ class StructuredDataSet:
164
163
  structured_row = structured_row_template.create_row()
165
164
  for column_name, value in row.items():
166
165
  structured_row_template.set_value(structured_row, column_name, value, reader.file, reader.row_number)
167
- if self._autoadd_properties:
168
- self._add_properties(structured_row, self._autoadd_properties, schema)
169
166
  self._add(type_name, structured_row)
170
167
  self._note_warning(reader.warnings, "reader")
171
168
  if schema:
172
169
  self._note_error(schema._unresolved_refs, "ref")
173
- self._resolved_refs.update(schema._resolved_refs)
170
+ self._resolved_refs = schema._resolved_refs
174
171
 
175
172
  def _add(self, type_name: str, data: Union[dict, List[dict]]) -> None:
176
173
  if self._prune:
@@ -180,11 +177,6 @@ class StructuredDataSet:
180
177
  else:
181
178
  self.data[type_name] = [data] if isinstance(data, dict) else data
182
179
 
183
- def _add_properties(self, structured_row: dict, properties: dict, schema: Optional[dict] = None) -> None:
184
- for name in properties:
185
- if name not in structured_row and (not schema or schema.data.get("properties", {}).get(name)):
186
- structured_row[name] = properties[name]
187
-
188
180
  def _note_warning(self, item: Optional[Union[dict, List[dict]]], group: str) -> None:
189
181
  self._note_issue(self._warnings, item, group)
190
182
 
@@ -245,7 +237,7 @@ class _StructuredRowTemplate:
245
237
  return {array_name: array} if array_name else {column_component: value}
246
238
 
247
239
  def set_value_internal(data: Union[dict, list], value: Optional[Any], src: Optional[str],
248
- path: List[Union[str, int]], typeinfo: Optional[dict], mapv: Optional[Callable]) -> None:
240
+ path: List[Union[str, int]], mapv: Optional[Callable]) -> None:
249
241
 
250
242
  def set_value_backtrack_object(path_index: int, path_element: str) -> None:
251
243
  nonlocal data, path, original_data
@@ -265,7 +257,7 @@ class _StructuredRowTemplate:
265
257
  set_value_backtrack_object(i, p)
266
258
  data = data[p]
267
259
  if (p := path[-1]) == -1 and isinstance(value, str):
268
- values = _split_array_string(value, unique=typeinfo.get("unique") if typeinfo else False)
260
+ values = _split_array_string(value)
269
261
  if mapv:
270
262
  values = [mapv(value, src) for value in values]
271
263
  merge_objects(data, values)
@@ -296,13 +288,11 @@ class _StructuredRowTemplate:
296
288
  for column_name in column_names or []:
297
289
  ensure_column_consistency(column_name)
298
290
  rational_column_name = self._schema.rationalize_column_name(column_name) if self._schema else column_name
299
- column_typeinfo = self._schema.get_typeinfo(rational_column_name) if self._schema else None
300
- map_value_function = column_typeinfo.get("map") if column_typeinfo else None
291
+ map_value_function = self._schema.get_map_value_function(rational_column_name) if self._schema else None
301
292
  if (column_components := _split_dotted_string(rational_column_name)):
302
293
  merge_objects(structured_row_template, parse_components(column_components, path := []), True)
303
- self._set_value_functions[column_name] = (
304
- lambda data, value, src, path=path, typeinfo=column_typeinfo, mapv=map_value_function:
305
- set_value_internal(data, value, src, path, typeinfo, mapv))
294
+ self._set_value_functions[column_name] = (lambda data, value, src, path=path, mapv=map_value_function:
295
+ set_value_internal(data, value, src, path, mapv))
306
296
  return structured_row_template
307
297
 
308
298
 
@@ -325,8 +315,7 @@ class Schema:
325
315
 
326
316
  @staticmethod
327
317
  def load_by_name(name: str, portal: Portal) -> Optional[dict]:
328
- schema_json = portal.get_schema(Schema.type_name(name)) if portal else None
329
- return Schema(schema_json, portal) if schema_json else None
318
+ return Schema(portal.get_schema(Schema.type_name(name)), portal) if portal else None
330
319
 
331
320
  def validate(self, data: dict) -> List[str]:
332
321
  errors = []
@@ -342,7 +331,10 @@ class Schema:
342
331
  def resolved_refs(self) -> List[str]:
343
332
  return list(self._resolved_refs)
344
333
 
345
- def get_typeinfo(self, column_name: str) -> Optional[dict]:
334
+ def get_map_value_function(self, column_name: str) -> Optional[Any]:
335
+ return (self._get_typeinfo(column_name) or {}).get("map")
336
+
337
+ def _get_typeinfo(self, column_name: str) -> Optional[dict]:
346
338
  if isinstance(info := self._typeinfo.get(column_name), str):
347
339
  info = self._typeinfo.get(info)
348
340
  if not info and isinstance(info := self._typeinfo.get(self.unadorn_column_name(column_name)), str):
@@ -475,15 +467,9 @@ class Schema:
475
467
  raise Exception(f"Array of undefined or multiple types in JSON schema NOT supported: {key}")
476
468
  raise Exception(f"Invalid array type specifier in JSON schema: {key}")
477
469
  key = key + ARRAY_NAME_SUFFIX_CHAR
478
- if unique := (property_value.get("uniqueItems") is True):
479
- pass
480
470
  property_value = array_property_items
481
471
  property_value_type = property_value.get("type")
482
- typeinfo = self._create_typeinfo(array_property_items, parent_key=key)
483
- if unique:
484
- typeinfo[key]["unique"] = True
485
- result.update(typeinfo)
486
- # result.update(self._create_typeinfo(array_property_items, parent_key=key))
472
+ result.update(self._create_typeinfo(array_property_items, parent_key=key))
487
473
  continue
488
474
  result[key] = {"type": property_value_type, "map": self._map_function({**property_value, "column": key})}
489
475
  if ARRAY_NAME_SUFFIX_CHAR in key:
@@ -574,9 +560,7 @@ class Portal(PortalBase):
574
560
 
575
561
  @lru_cache(maxsize=256)
576
562
  def get_schema(self, schema_name: str) -> Optional[dict]:
577
- if not (schemas := self.get_schemas()):
578
- return None
579
- if schema := schemas.get(schema_name := Schema.type_name(schema_name)):
563
+ if (schemas := self.get_schemas()) and (schema := schemas.get(schema_name := Schema.type_name(schema_name))):
580
564
  return schema
581
565
  if schema_name == schema_name.upper() and (schema := schemas.get(schema_name.lower().title())):
582
566
  return schema
@@ -584,9 +568,8 @@ class Portal(PortalBase):
584
568
  return schema
585
569
 
586
570
  @lru_cache(maxsize=1)
587
- def get_schemas(self) -> Optional[dict]:
588
- if not (schemas := super().get_schemas()) or (schemas.get("status") == "error"):
589
- return None
571
+ def get_schemas(self) -> dict:
572
+ schemas = super().get_schemas()
590
573
  if self._schemas:
591
574
  schemas = copy.deepcopy(schemas)
592
575
  for user_specified_schema in self._schemas:
@@ -632,5 +615,5 @@ def _split_dotted_string(value: str):
632
615
  return split_string(value, DOTTED_NAME_DELIMITER_CHAR)
633
616
 
634
617
 
635
- def _split_array_string(value: str, unique: bool = False):
636
- return split_string(value, ARRAY_VALUE_DELIMITER_CHAR, ARRAY_VALUE_DELIMITER_ESCAPE_CHAR, unique=unique)
618
+ def _split_array_string(value: str):
619
+ return split_string(value, ARRAY_VALUE_DELIMITER_CHAR, ARRAY_VALUE_DELIMITER_ESCAPE_CHAR)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dcicutils
3
- Version: 8.5.0.1b4
3
+ Version: 8.6.0.0b0
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
@@ -40,30 +40,31 @@ dcicutils/license_policies/park-lab-gpl-pipeline.jsonc,sha256=vLZkwm3Js-kjV44nug
40
40
  dcicutils/license_policies/park-lab-pipeline.jsonc,sha256=9qlY0ASy3iUMQlr3gorVcXrSfRHnVGbLhkS427UaRy4,283
41
41
  dcicutils/license_utils.py,sha256=d1cq6iwv5Ju-VjdoINi6q7CPNNL7Oz6rcJdLMY38RX0,46978
42
42
  dcicutils/log_utils.py,sha256=7pWMc6vyrorUZQf-V-M3YC6zrPgNhuV_fzm9xqTPph0,10883
43
- dcicutils/misc_utils.py,sha256=nRjLEORY35YmJwTjO0fnauBPznaI_bkVasIW8PccDYM,100179
43
+ dcicutils/misc_utils.py,sha256=slnJM87VrPj2gCiQR8Yrl8bwTjeynXpM1yKIjJg8NN4,99816
44
44
  dcicutils/obfuscation_utils.py,sha256=fo2jOmDRC6xWpYX49u80bVNisqRRoPskFNX3ymFAmjw,5963
45
45
  dcicutils/opensearch_utils.py,sha256=V2exmFYW8Xl2_pGFixF4I2Cc549Opwe4PhFi5twC0M8,1017
46
- dcicutils/portal_utils.py,sha256=Wh918ZKpUJFbt7w6Bn5G7v-0k6ImOUWMFmE9Oxt1ZN4,14560
46
+ dcicutils/portal_utils.py,sha256=OF1JPoDgEbvCvPKz0egcnmqGEOYWkamuBLRN_RpZFtk,14073
47
47
  dcicutils/project_utils.py,sha256=qPdCaFmWUVBJw4rw342iUytwdQC0P-XKpK4mhyIulMM,31250
48
48
  dcicutils/qa_checkers.py,sha256=cdXjeL0jCDFDLT8VR8Px78aS10hwNISOO5G_Zv2TZ6M,20534
49
49
  dcicutils/qa_utils.py,sha256=TT0SiJWiuxYvbsIyhK9VO4uV_suxhB6CpuC4qPacCzQ,160208
50
50
  dcicutils/redis_tools.py,sha256=qkcSNMtvqkpvts-Cm9gWhneK523Q_oHwhNUud1be1qk,7055
51
51
  dcicutils/redis_utils.py,sha256=VJ-7g8pOZqR1ZCtdcjKz3-6as2DMUcs1b1zG6wSprH4,6462
52
52
  dcicutils/s3_utils.py,sha256=eN8lfDI8Yxqga7iuy_eOlmUJUEjewHho0szLmj2YmYI,28852
53
+ dcicutils/schema_utils.py,sha256=xlvY7BuIhjJYk7GKYamhbHDw1751rmYcEM2pOaEH1BY,4203
53
54
  dcicutils/scripts/publish_to_pypi.py,sha256=qmWyjrg5bNQNfpNKFTZdyMXpRmrECnRV9VmNQddUPQA,13576
54
55
  dcicutils/scripts/run_license_checker.py,sha256=z2keYnRDZsHQbTeo1XORAXSXNJK5axVzL5LjiNqZ7jE,4184
55
56
  dcicutils/secrets_utils.py,sha256=8dppXAsiHhJzI6NmOcvJV5ldvKkQZzh3Fl-cb8Wm7MI,19745
56
57
  dcicutils/sheet_utils.py,sha256=VlmzteONW5VF_Q4vo0yA5vesz1ViUah1MZ_yA1rwZ0M,33629
57
58
  dcicutils/snapshot_utils.py,sha256=ymP7PXH6-yEiXAt75w0ldQFciGNqWBClNxC5gfX2FnY,22961
58
59
  dcicutils/ssl_certificate_utils.py,sha256=F0ifz_wnRRN9dfrfsz7aCp4UDLgHEY8LaK7PjnNvrAQ,9707
59
- dcicutils/structured_data.py,sha256=tMKBhq6OuM2t6iDxIPBFcxV66MiwmOHTBeACxhvkbiQ,33307
60
+ dcicutils/structured_data.py,sha256=bOzashl_cy5c8NWewcPpRPknQDbSPstL_3Cw2-KUSl0,32112
60
61
  dcicutils/task_utils.py,sha256=MF8ujmTD6-O2AC2gRGPHyGdUrVKgtr8epT5XU8WtNjk,8082
61
62
  dcicutils/trace_utils.py,sha256=g8kwV4ebEy5kXW6oOrEAUsurBcCROvwtZqz9fczsGRE,1769
62
63
  dcicutils/validation_utils.py,sha256=cMZIU2cY98FYtzK52z5WUYck7urH6JcqOuz9jkXpqzg,14797
63
64
  dcicutils/variant_utils.py,sha256=2H9azNx3xAj-MySg-uZ2SFqbWs4kZvf61JnK6b-h4Qw,4343
64
65
  dcicutils/zip_utils.py,sha256=0OXR0aLNwyLIZOzIFTM_5DOun7dxIv6TIZbFiithkO0,3276
65
- dcicutils-8.5.0.1b4.dist-info/LICENSE.txt,sha256=t0_-jIjqxNnymZoNJe-OltRIuuF8qfhN0ATlHyrUJPk,1102
66
- dcicutils-8.5.0.1b4.dist-info/METADATA,sha256=Zpf8fTsgsuRfo8WDGkONHxtcf4SPWOFK_4iCNVAhB78,3314
67
- dcicutils-8.5.0.1b4.dist-info/WHEEL,sha256=7Z8_27uaHI_UZAc4Uox4PpBhQ9Y5_modZXWMxtUi4NU,88
68
- dcicutils-8.5.0.1b4.dist-info/entry_points.txt,sha256=8wbw5csMIgBXhkwfgsgJeuFcoUc0WsucUxmOyml2aoA,209
69
- dcicutils-8.5.0.1b4.dist-info/RECORD,,
66
+ dcicutils-8.6.0.0b0.dist-info/LICENSE.txt,sha256=t0_-jIjqxNnymZoNJe-OltRIuuF8qfhN0ATlHyrUJPk,1102
67
+ dcicutils-8.6.0.0b0.dist-info/METADATA,sha256=Wbkp0zSdhveaLePg7P-jFS06WfiHGMn30IQq2RxhN6g,3314
68
+ dcicutils-8.6.0.0b0.dist-info/WHEEL,sha256=7Z8_27uaHI_UZAc4Uox4PpBhQ9Y5_modZXWMxtUi4NU,88
69
+ dcicutils-8.6.0.0b0.dist-info/entry_points.txt,sha256=8wbw5csMIgBXhkwfgsgJeuFcoUc0WsucUxmOyml2aoA,209
70
+ dcicutils-8.6.0.0b0.dist-info/RECORD,,