dcicutils 8.5.0.1b4__py3-none-any.whl → 8.6.0.0b0__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 +7 -16
- dcicutils/portal_utils.py +8 -23
- dcicutils/schema_utils.py +142 -0
- dcicutils/structured_data.py +23 -40
- {dcicutils-8.5.0.1b4.dist-info → dcicutils-8.6.0.0b0.dist-info}/METADATA +1 -1
- {dcicutils-8.5.0.1b4.dist-info → dcicutils-8.6.0.0b0.dist-info}/RECORD +9 -8
- {dcicutils-8.5.0.1b4.dist-info → dcicutils-8.6.0.0b0.dist-info}/LICENSE.txt +0 -0
- {dcicutils-8.5.0.1b4.dist-info → dcicutils-8.6.0.0b0.dist-info}/WHEEL +0 -0
- {dcicutils-8.5.0.1b4.dist-info → dcicutils-8.6.0.0b0.dist-info}/entry_points.txt +0 -0
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
|
-
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
1497
|
-
|
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
|
27
|
-
and with a dictionary value containing "key" and "secret" property values
|
28
|
-
|
29
|
-
will be used, i.e. e.g. if
|
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
|
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
|
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
|
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)
|
dcicutils/structured_data.py
CHANGED
@@ -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,
|
46
|
-
|
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 =
|
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,
|
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,
|
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
|
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
|
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]],
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
-
|
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
|
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) ->
|
588
|
-
|
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
|
636
|
-
return split_string(value, ARRAY_VALUE_DELIMITER_CHAR, ARRAY_VALUE_DELIMITER_ESCAPE_CHAR
|
618
|
+
def _split_array_string(value: str):
|
619
|
+
return split_string(value, ARRAY_VALUE_DELIMITER_CHAR, ARRAY_VALUE_DELIMITER_ESCAPE_CHAR)
|
@@ -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=
|
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=
|
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=
|
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.
|
66
|
-
dcicutils-8.
|
67
|
-
dcicutils-8.
|
68
|
-
dcicutils-8.
|
69
|
-
dcicutils-8.
|
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,,
|
File without changes
|
File without changes
|
File without changes
|