dcicutils 8.7.1.1b5__py3-none-any.whl → 8.7.1.1b6__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 +13 -0
- dcicutils/portal_object_utils.py +27 -13
- dcicutils/structured_data.py +1 -1
- {dcicutils-8.7.1.1b5.dist-info → dcicutils-8.7.1.1b6.dist-info}/METADATA +1 -1
- {dcicutils-8.7.1.1b5.dist-info → dcicutils-8.7.1.1b6.dist-info}/RECORD +8 -8
- {dcicutils-8.7.1.1b5.dist-info → dcicutils-8.7.1.1b6.dist-info}/LICENSE.txt +0 -0
- {dcicutils-8.7.1.1b5.dist-info → dcicutils-8.7.1.1b6.dist-info}/WHEEL +0 -0
- {dcicutils-8.7.1.1b5.dist-info → dcicutils-8.7.1.1b6.dist-info}/entry_points.txt +0 -0
dcicutils/misc_utils.py
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
This file contains functions that might be generally useful.
|
3
3
|
"""
|
4
4
|
|
5
|
+
from collections import namedtuple
|
5
6
|
import contextlib
|
6
7
|
import datetime
|
7
8
|
import functools
|
@@ -17,6 +18,7 @@ import re
|
|
17
18
|
import rfc3986.validators
|
18
19
|
import rfc3986.exceptions
|
19
20
|
import time
|
21
|
+
import uuid
|
20
22
|
import warnings
|
21
23
|
import webtest # importing the library makes it easier to mock testing
|
22
24
|
|
@@ -1525,6 +1527,17 @@ def create_dict(**kwargs) -> dict:
|
|
1525
1527
|
return result
|
1526
1528
|
|
1527
1529
|
|
1530
|
+
def create_readonly_object(**kwargs):
|
1531
|
+
"""
|
1532
|
+
Returns a new/unique object instance with readonly properties equal to the give kwargs.
|
1533
|
+
"""
|
1534
|
+
readonly_class_name = "readonlyclass_" + str(uuid.uuid4()).replace("-", "")
|
1535
|
+
readonly_class_args = " ".join(kwargs.keys())
|
1536
|
+
readonly_class = namedtuple(readonly_class_name, readonly_class_args)
|
1537
|
+
readonly_object = readonly_class(**kwargs)
|
1538
|
+
return readonly_object
|
1539
|
+
|
1540
|
+
|
1528
1541
|
def is_c4_arn(arn: str) -> bool:
|
1529
1542
|
"""
|
1530
1543
|
Returns True iff the given (presumed) AWS ARN string value looks like it
|
dcicutils/portal_object_utils.py
CHANGED
@@ -3,6 +3,7 @@ from functools import lru_cache
|
|
3
3
|
import re
|
4
4
|
from typing import Any, List, Optional, Tuple, Type, Union
|
5
5
|
from dcicutils.data_readers import RowReader
|
6
|
+
from dcicutils.misc_utils import create_readonly_object
|
6
7
|
from dcicutils.portal_utils import Portal
|
7
8
|
from dcicutils.schema_utils import Schema
|
8
9
|
|
@@ -136,21 +137,33 @@ class PortalObject:
|
|
136
137
|
comparing_data = value
|
137
138
|
else:
|
138
139
|
return {}
|
139
|
-
return PortalObject._compare(this_data, comparing_data)
|
140
|
+
return PortalObject._compare(this_data, comparing_data, self.type)
|
140
141
|
|
141
142
|
_ARRAY_KEY_REGULAR_EXPRESSION = re.compile(rf"^({Schema._ARRAY_NAME_SUFFIX_CHAR}\d+)$")
|
142
143
|
|
143
144
|
@staticmethod
|
144
|
-
def _compare(a: Any, b: Any, _path: Optional[str] = None) -> dict:
|
145
|
+
def _compare(a: Any, b: Any, value_type: str, _path: Optional[str] = None) -> dict:
|
146
|
+
def diff_creating(value: Any) -> object: # noqa
|
147
|
+
nonlocal value_type
|
148
|
+
return create_readonly_object(value=value, type=value_type,
|
149
|
+
creating_value=True, updating_value=None, deleting_value=False)
|
150
|
+
def diff_updating(value: Any, updating_value: Any) -> object: # noqa
|
151
|
+
nonlocal value_type
|
152
|
+
return create_readonly_object(value=value, type=value_type,
|
153
|
+
creating_value=False, updating_value=updating_value, deleting_value=False)
|
154
|
+
def diff_deleting(value: Any) -> object: # noqa
|
155
|
+
nonlocal value_type
|
156
|
+
return create_readonly_object(value=value, type=value_type,
|
157
|
+
creating_value=False, updating_value=None, deleting_value=True)
|
145
158
|
diffs = {}
|
146
159
|
if isinstance(a, dict) and isinstance(b, dict):
|
147
160
|
for key in a:
|
148
161
|
path = f"{_path}.{key}" if _path else key
|
149
162
|
if key not in b:
|
150
163
|
if a[key] != PortalObject._PROPERTY_DELETION_SENTINEL:
|
151
|
-
diffs[path] =
|
164
|
+
diffs[path] = diff_creating(a[key])
|
152
165
|
else:
|
153
|
-
diffs.update(PortalObject._compare(a[key], b[key], _path=path))
|
166
|
+
diffs.update(PortalObject._compare(a[key], b[key], type, _path=path))
|
154
167
|
elif isinstance(a, list) and isinstance(b, list):
|
155
168
|
# Ignore order of array elements; not absolutely technically correct but suits our purpose.
|
156
169
|
for index in range(len(a)):
|
@@ -159,21 +172,21 @@ class PortalObject:
|
|
159
172
|
if a[index] not in b:
|
160
173
|
if a[index] != PortalObject._PROPERTY_DELETION_SENTINEL:
|
161
174
|
if index < len(b):
|
162
|
-
diffs[path] =
|
175
|
+
diffs[path] = diff_updating(a[index], b[index])
|
163
176
|
else:
|
164
|
-
diffs[path] =
|
177
|
+
diffs[path] = diff_creating(a[index])
|
165
178
|
else:
|
166
179
|
if index < len(b):
|
167
|
-
diffs[path] =
|
180
|
+
diffs[path] = diff_deleting(b[index])
|
168
181
|
elif len(b) < index:
|
169
|
-
diffs.update(PortalObject._compare(a[index], b[index], _path=path))
|
182
|
+
diffs.update(PortalObject._compare(a[index], b[index], value_type, _path=path))
|
170
183
|
else:
|
171
|
-
diffs[path] =
|
184
|
+
diffs[path] = diff_creating(a[index])
|
172
185
|
elif a != b:
|
173
186
|
if a == PortalObject._PROPERTY_DELETION_SENTINEL:
|
174
|
-
diffs[_path] =
|
187
|
+
diffs[_path] = diff_deleting(b)
|
175
188
|
else:
|
176
|
-
diffs[_path] =
|
189
|
+
diffs[_path] = diff_updating(a, b)
|
177
190
|
return diffs
|
178
191
|
|
179
192
|
def normalize_refs(self, refs: List[dict]) -> None:
|
@@ -183,8 +196,9 @@ class PortalObject:
|
|
183
196
|
based on the given "refs" list which is assumed to be a list of dictionaries, where each
|
184
197
|
contains a "path" and a "uuid" property; this list is typically (for our first usage of
|
185
198
|
this function) the value of structured_data.StructuredDataSet.resolved_refs_with_uuid.
|
186
|
-
|
187
|
-
If there are no "refs" (None or empty)
|
199
|
+
Changes are made to this Portal object in place; use normalized_refs function to make a copy.
|
200
|
+
If there are no "refs" (None or empty) or if the speicified reference is not found in this
|
201
|
+
list then the references will be looked up via Portal calls (via Portal.get_metadata).
|
188
202
|
"""
|
189
203
|
PortalObject._normalize_refs(self.data, refs=refs, schema=self.schema, portal=self.portal)
|
190
204
|
|
dcicutils/structured_data.py
CHANGED
@@ -369,7 +369,7 @@ class Schema:
|
|
369
369
|
def validate(self, data: dict) -> List[str]:
|
370
370
|
errors = []
|
371
371
|
for error in SchemaValidator(self.data, format_checker=SchemaValidator.FORMAT_CHECKER).iter_errors(data):
|
372
|
-
errors.append(error.message)
|
372
|
+
errors.append(f"Validation error at '{error.json_path}': {error.message}")
|
373
373
|
return errors
|
374
374
|
|
375
375
|
def get_typeinfo(self, column_name: str) -> Optional[dict]:
|
@@ -41,10 +41,10 @@ dcicutils/license_policies/park-lab-gpl-pipeline.jsonc,sha256=vLZkwm3Js-kjV44nug
|
|
41
41
|
dcicutils/license_policies/park-lab-pipeline.jsonc,sha256=9qlY0ASy3iUMQlr3gorVcXrSfRHnVGbLhkS427UaRy4,283
|
42
42
|
dcicutils/license_utils.py,sha256=d1cq6iwv5Ju-VjdoINi6q7CPNNL7Oz6rcJdLMY38RX0,46978
|
43
43
|
dcicutils/log_utils.py,sha256=7pWMc6vyrorUZQf-V-M3YC6zrPgNhuV_fzm9xqTPph0,10883
|
44
|
-
dcicutils/misc_utils.py,sha256=
|
44
|
+
dcicutils/misc_utils.py,sha256=9JqdVjHLkZUDTryngF3Dbu0m7XcbitbR7izWnxUSWc4,101953
|
45
45
|
dcicutils/obfuscation_utils.py,sha256=fo2jOmDRC6xWpYX49u80bVNisqRRoPskFNX3ymFAmjw,5963
|
46
46
|
dcicutils/opensearch_utils.py,sha256=V2exmFYW8Xl2_pGFixF4I2Cc549Opwe4PhFi5twC0M8,1017
|
47
|
-
dcicutils/portal_object_utils.py,sha256=
|
47
|
+
dcicutils/portal_object_utils.py,sha256=Aa61u0o9OyWR7M26dGceMW9MSgDEZLqrwAkwu8FD228,12445
|
48
48
|
dcicutils/portal_utils.py,sha256=8XVRCy882RrB8QT2gGvW36c4nT1RJCgUApt_wLP-EG8,26706
|
49
49
|
dcicutils/project_utils.py,sha256=qPdCaFmWUVBJw4rw342iUytwdQC0P-XKpK4mhyIulMM,31250
|
50
50
|
dcicutils/qa_checkers.py,sha256=cdXjeL0jCDFDLT8VR8Px78aS10hwNISOO5G_Zv2TZ6M,20534
|
@@ -59,15 +59,15 @@ dcicutils/secrets_utils.py,sha256=8dppXAsiHhJzI6NmOcvJV5ldvKkQZzh3Fl-cb8Wm7MI,19
|
|
59
59
|
dcicutils/sheet_utils.py,sha256=VlmzteONW5VF_Q4vo0yA5vesz1ViUah1MZ_yA1rwZ0M,33629
|
60
60
|
dcicutils/snapshot_utils.py,sha256=ymP7PXH6-yEiXAt75w0ldQFciGNqWBClNxC5gfX2FnY,22961
|
61
61
|
dcicutils/ssl_certificate_utils.py,sha256=F0ifz_wnRRN9dfrfsz7aCp4UDLgHEY8LaK7PjnNvrAQ,9707
|
62
|
-
dcicutils/structured_data.py,sha256=
|
62
|
+
dcicutils/structured_data.py,sha256=voFT8RqVXLX6-sZiEfhsgmwXEiMcJUrHneYUDXNm9wk,35647
|
63
63
|
dcicutils/task_utils.py,sha256=MF8ujmTD6-O2AC2gRGPHyGdUrVKgtr8epT5XU8WtNjk,8082
|
64
64
|
dcicutils/tmpfile_utils.py,sha256=n95XF8dZVbQRSXBZTGToXXfSs3JUVRyN6c3ZZ0nhAWI,1403
|
65
65
|
dcicutils/trace_utils.py,sha256=g8kwV4ebEy5kXW6oOrEAUsurBcCROvwtZqz9fczsGRE,1769
|
66
66
|
dcicutils/validation_utils.py,sha256=cMZIU2cY98FYtzK52z5WUYck7urH6JcqOuz9jkXpqzg,14797
|
67
67
|
dcicutils/variant_utils.py,sha256=2H9azNx3xAj-MySg-uZ2SFqbWs4kZvf61JnK6b-h4Qw,4343
|
68
68
|
dcicutils/zip_utils.py,sha256=rnjNv_k6L9jT2SjDSgVXp4BEJYLtz9XN6Cl2Fy-tqnM,2027
|
69
|
-
dcicutils-8.7.1.
|
70
|
-
dcicutils-8.7.1.
|
71
|
-
dcicutils-8.7.1.
|
72
|
-
dcicutils-8.7.1.
|
73
|
-
dcicutils-8.7.1.
|
69
|
+
dcicutils-8.7.1.1b6.dist-info/LICENSE.txt,sha256=qnwSmfnEWMl5l78VPDEzAmEbLVrRqQvfUQiHT0ehrOo,1102
|
70
|
+
dcicutils-8.7.1.1b6.dist-info/METADATA,sha256=YLm-JVegaODLOnyLLQgUzFTwUPRlK-9dn0eZP1ANmHY,3314
|
71
|
+
dcicutils-8.7.1.1b6.dist-info/WHEEL,sha256=7Z8_27uaHI_UZAc4Uox4PpBhQ9Y5_modZXWMxtUi4NU,88
|
72
|
+
dcicutils-8.7.1.1b6.dist-info/entry_points.txt,sha256=8wbw5csMIgBXhkwfgsgJeuFcoUc0WsucUxmOyml2aoA,209
|
73
|
+
dcicutils-8.7.1.1b6.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|