dcicutils 8.7.1.1b9__py3-none-any.whl → 8.7.1.1b12__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/portal_object_utils.py +32 -27
- dcicutils/portal_utils.py +1 -1
- dcicutils/schema_utils.py +2 -2
- dcicutils/structured_data.py +12 -10
- {dcicutils-8.7.1.1b9.dist-info → dcicutils-8.7.1.1b12.dist-info}/METADATA +1 -1
- {dcicutils-8.7.1.1b9.dist-info → dcicutils-8.7.1.1b12.dist-info}/RECORD +9 -9
- {dcicutils-8.7.1.1b9.dist-info → dcicutils-8.7.1.1b12.dist-info}/LICENSE.txt +0 -0
- {dcicutils-8.7.1.1b9.dist-info → dcicutils-8.7.1.1b12.dist-info}/WHEEL +0 -0
- {dcicutils-8.7.1.1b9.dist-info → dcicutils-8.7.1.1b12.dist-info}/entry_points.txt +0 -0
dcicutils/portal_object_utils.py
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
from copy import deepcopy
|
2
2
|
from functools import lru_cache
|
3
|
-
import re
|
4
3
|
from typing import Any, List, Optional, Tuple, Type, Union
|
5
4
|
from dcicutils.data_readers import RowReader
|
6
5
|
from dcicutils.misc_utils import create_readonly_object
|
@@ -14,28 +13,28 @@ class PortalObject:
|
|
14
13
|
|
15
14
|
_PROPERTY_DELETION_SENTINEL = RowReader.CELL_DELETION_SENTINEL
|
16
15
|
|
17
|
-
def __init__(self,
|
18
|
-
self._portal = portal
|
16
|
+
def __init__(self, portal_object: dict, portal: Portal = None, type: Optional[str] = None) -> None:
|
19
17
|
self._data = portal_object
|
20
|
-
self.
|
18
|
+
self._portal = portal
|
19
|
+
self._type = type if isinstance(type, str) and type else None
|
21
20
|
|
22
21
|
@property
|
23
|
-
def data(self):
|
22
|
+
def data(self) -> dict:
|
24
23
|
return self._data
|
25
24
|
|
26
25
|
@property
|
27
|
-
def portal(self):
|
26
|
+
def portal(self) -> Optional[Portal]:
|
28
27
|
return self._portal
|
29
28
|
|
30
29
|
@property
|
31
30
|
@lru_cache(maxsize=1)
|
32
|
-
def type(self):
|
31
|
+
def type(self) -> Optional[str]:
|
33
32
|
return self._type or Portal.get_schema_type(self._data)
|
34
33
|
|
35
34
|
@property
|
36
35
|
@lru_cache(maxsize=1)
|
37
|
-
def types(self):
|
38
|
-
return self._type
|
36
|
+
def types(self) -> Optional[List[str]]:
|
37
|
+
return [self._type] if self._type else Portal.get_schema_types(self._data)
|
39
38
|
|
40
39
|
@property
|
41
40
|
@lru_cache(maxsize=1)
|
@@ -44,22 +43,22 @@ class PortalObject:
|
|
44
43
|
|
45
44
|
@property
|
46
45
|
@lru_cache(maxsize=1)
|
47
|
-
def schema(self):
|
48
|
-
return self._portal.get_schema(self.type)
|
46
|
+
def schema(self) -> Optional[dict]:
|
47
|
+
return self._portal.get_schema(self.type) if self._portal else None
|
49
48
|
|
50
49
|
def copy(self) -> PortalObject:
|
51
|
-
return PortalObject(
|
50
|
+
return PortalObject(deepcopy(self.data), portal=self.portal, type=self.type)
|
52
51
|
|
53
52
|
@property
|
54
53
|
@lru_cache(maxsize=1)
|
55
|
-
def identifying_properties(self) -> List[str]:
|
54
|
+
def identifying_properties(self) -> Optional[List[str]]:
|
56
55
|
"""
|
57
56
|
Returns the list of all identifying property names of this Portal object which actually have values.
|
58
57
|
Implicitly include "uuid" and "identifier" properties as identifying properties if they are actually
|
59
58
|
properties in the object schema, and favor these (first); defavor "aliases"; no other ordering defined.
|
60
59
|
"""
|
61
60
|
if not (schema := self.schema) or not (schema_identifying_properties := schema.get("identifyingProperties")):
|
62
|
-
return
|
61
|
+
return None
|
63
62
|
identifying_properties = []
|
64
63
|
for identifying_property in schema_identifying_properties:
|
65
64
|
if identifying_property not in ["uuid", "identifier", "aliases"]:
|
@@ -71,17 +70,21 @@ class PortalObject:
|
|
71
70
|
identifying_properties.insert(0, "uuid")
|
72
71
|
if "aliases" in schema_identifying_properties and self._data.get("aliases"):
|
73
72
|
identifying_properties.append("aliases")
|
74
|
-
return identifying_properties
|
73
|
+
return identifying_properties or None
|
75
74
|
|
76
75
|
@property
|
77
76
|
@lru_cache(maxsize=1)
|
78
|
-
def identifying_paths(self) -> List[str]:
|
77
|
+
def identifying_paths(self) -> Optional[List[str]]:
|
79
78
|
"""
|
80
79
|
Returns a list of the possible Portal URL paths identifying this Portal object.
|
81
80
|
"""
|
82
|
-
if not (identifying_properties := self.identifying_properties):
|
83
|
-
return []
|
84
81
|
identifying_paths = []
|
82
|
+
if not (identifying_properties := self.identifying_properties):
|
83
|
+
if self.uuid:
|
84
|
+
if self.type:
|
85
|
+
identifying_paths.append(f"/{self.type}/{self.uuid}")
|
86
|
+
identifying_paths.append(f"/{self.uuid}")
|
87
|
+
return identifying_paths
|
85
88
|
for identifying_property in identifying_properties:
|
86
89
|
if (identifying_value := self._data.get(identifying_property)):
|
87
90
|
if identifying_property == "uuid":
|
@@ -96,12 +99,14 @@ class PortalObject:
|
|
96
99
|
# not work but /FileSet/UW_FILE-SET_COLO-829BL_HI-C_1 does work.
|
97
100
|
elif isinstance(identifying_value, list):
|
98
101
|
for identifying_value_item in identifying_value:
|
99
|
-
|
102
|
+
if self.type:
|
103
|
+
identifying_paths.append(f"/{self.type}/{identifying_value_item}")
|
100
104
|
identifying_paths.append(f"/{identifying_value_item}")
|
101
105
|
else:
|
102
|
-
|
106
|
+
if self.type:
|
107
|
+
identifying_paths.append(f"/{self.type}/{identifying_value}")
|
103
108
|
identifying_paths.append(f"/{identifying_value}")
|
104
|
-
return identifying_paths
|
109
|
+
return identifying_paths or None
|
105
110
|
|
106
111
|
@property
|
107
112
|
@lru_cache(maxsize=1)
|
@@ -118,9 +123,11 @@ class PortalObject:
|
|
118
123
|
|
119
124
|
def _lookup(self, raw: bool = False) -> Tuple[Optional[PortalObject], Optional[str]]:
|
120
125
|
try:
|
121
|
-
|
122
|
-
|
123
|
-
|
126
|
+
if identifying_paths := self.identifying_paths:
|
127
|
+
for identifying_path in identifying_paths:
|
128
|
+
if (value := self._portal.get(identifying_path, raw=raw)) and (value.status_code == 200):
|
129
|
+
return PortalObject(value.json(),
|
130
|
+
portal=self._portal, type=self.type if raw else None), identifying_path
|
124
131
|
except Exception:
|
125
132
|
pass
|
126
133
|
return None, self.identifying_path
|
@@ -139,8 +146,6 @@ class PortalObject:
|
|
139
146
|
return {}
|
140
147
|
return PortalObject._compare(this_data, comparing_data)
|
141
148
|
|
142
|
-
_ARRAY_KEY_REGULAR_EXPRESSION = re.compile(rf"^({Schema._ARRAY_NAME_SUFFIX_CHAR}\d+)$")
|
143
|
-
|
144
149
|
@staticmethod
|
145
150
|
def _compare(a: Any, b: Any, _path: Optional[str] = None) -> dict:
|
146
151
|
def diff_creating(value: Any) -> object: # noqa
|
@@ -175,7 +180,7 @@ class PortalObject:
|
|
175
180
|
else:
|
176
181
|
if index < len(b):
|
177
182
|
diffs[path] = diff_deleting(b[index])
|
178
|
-
elif len(b)
|
183
|
+
elif index < len(b):
|
179
184
|
diffs.update(PortalObject._compare(a[index], b[index], _path=path))
|
180
185
|
else:
|
181
186
|
diffs[path] = diff_creating(a[index])
|
dcicutils/portal_utils.py
CHANGED
@@ -28,7 +28,7 @@ class Portal:
|
|
28
28
|
"""
|
29
29
|
This is meant to be an Über wrapper for Portal access. It can be created in a variety of ways:
|
30
30
|
1. From a (Portal) .ini file (e.g. development.ini).
|
31
|
-
2. From a key dictionary, containing "key" and "secret" property values.
|
31
|
+
2. From a key dictionary, containing "key" and "secret" and (optional) "server" property values.
|
32
32
|
3. From a key pair tuple, containing (in order) a key and secret values.
|
33
33
|
4. From a keys .json file residing in ~/.{app}-keys.json where the given "app" value is either "smaht", "cgap",
|
34
34
|
or "fourfront"; where is assumed to contain a dictionary with a key for the given "env" value, e.g. smaht-local;
|
dcicutils/schema_utils.py
CHANGED
@@ -189,9 +189,9 @@ def get_one_of_formats(schema: Dict[str, Any]) -> List[str]:
|
|
189
189
|
|
190
190
|
class Schema:
|
191
191
|
|
192
|
-
def __init__(self, schema: dict,
|
192
|
+
def __init__(self, schema: dict, type: Optional[str] = None) -> None:
|
193
193
|
self._data = schema if isinstance(schema, dict) else (schema.data if isinstance(schema, Schema) else {})
|
194
|
-
self._type = (isinstance(
|
194
|
+
self._type = (type if isinstance(type, str) else "") or Schema.type_name(self._data.get("title", ""))
|
195
195
|
|
196
196
|
@property
|
197
197
|
def data(self) -> dict:
|
dcicutils/structured_data.py
CHANGED
@@ -16,6 +16,7 @@ from dcicutils.misc_utils import (create_dict, create_readonly_object, load_json
|
|
16
16
|
split_string, to_boolean, to_enum, to_float, to_integer, VirtualApp)
|
17
17
|
from dcicutils.portal_object_utils import PortalObject
|
18
18
|
from dcicutils.portal_utils import Portal as PortalBase
|
19
|
+
from dcicutils.schema_utils import Schema as SchemaBase
|
19
20
|
from dcicutils.zip_utils import unpack_gz_file_to_temporary_file, unpack_files
|
20
21
|
|
21
22
|
|
@@ -154,7 +155,7 @@ class StructuredDataSet:
|
|
154
155
|
if not diffs.get(object_type):
|
155
156
|
diffs[object_type] = []
|
156
157
|
for portal_object in self.data[object_type]:
|
157
|
-
portal_object = PortalObject(self.portal,
|
158
|
+
portal_object = PortalObject(portal_object, portal=self.portal, type=object_type)
|
158
159
|
existing_object, identifying_path = portal_object.lookup(include_identifying_path=True, raw=True)
|
159
160
|
if existing_object:
|
160
161
|
object_diffs = portal_object.compare(existing_object, consider_refs=True, resolved_refs=refs)
|
@@ -363,11 +364,12 @@ class _StructuredRowTemplate:
|
|
363
364
|
return structured_row_template
|
364
365
|
|
365
366
|
|
366
|
-
class Schema:
|
367
|
+
class Schema(SchemaBase):
|
367
368
|
|
368
369
|
def __init__(self, schema_json: dict, portal: Optional[Portal] = None) -> None:
|
369
|
-
|
370
|
-
|
370
|
+
super().__init__(schema_json)
|
371
|
+
# self._data = schema_json if isinstance(schema_json, dict) else {}
|
372
|
+
# self._type = Schema.type_name(schema_json.get("title", ""))
|
371
373
|
self._portal = portal # Needed only to resolve linkTo references.
|
372
374
|
self._map_value_functions = {
|
373
375
|
"boolean": self._map_function_boolean,
|
@@ -380,13 +382,13 @@ class Schema:
|
|
380
382
|
self._unresolved_refs = []
|
381
383
|
self._typeinfo = self._create_typeinfo(schema_json)
|
382
384
|
|
383
|
-
|
384
|
-
|
385
|
-
|
385
|
+
# @property
|
386
|
+
# def data(self) -> dict:
|
387
|
+
# return self._data
|
386
388
|
|
387
|
-
|
388
|
-
|
389
|
-
|
389
|
+
# @property
|
390
|
+
# def type(self) -> str:
|
391
|
+
# return self._type
|
390
392
|
|
391
393
|
@staticmethod
|
392
394
|
def load_by_name(name: str, portal: Portal) -> Optional[dict]:
|
@@ -44,30 +44,30 @@ dcicutils/log_utils.py,sha256=7pWMc6vyrorUZQf-V-M3YC6zrPgNhuV_fzm9xqTPph0,10883
|
|
44
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=
|
48
|
-
dcicutils/portal_utils.py,sha256=
|
47
|
+
dcicutils/portal_object_utils.py,sha256=cez8sLu9dyk5f4TrR2QoOPPjCK0m_Sns1FeW5gbdbVw,12686
|
48
|
+
dcicutils/portal_utils.py,sha256=5SfmAs_XEIeS26c6vWsujQgbyK7bACJVzqKgcTrE2SQ,27089
|
49
49
|
dcicutils/project_utils.py,sha256=qPdCaFmWUVBJw4rw342iUytwdQC0P-XKpK4mhyIulMM,31250
|
50
50
|
dcicutils/qa_checkers.py,sha256=cdXjeL0jCDFDLT8VR8Px78aS10hwNISOO5G_Zv2TZ6M,20534
|
51
51
|
dcicutils/qa_utils.py,sha256=TT0SiJWiuxYvbsIyhK9VO4uV_suxhB6CpuC4qPacCzQ,160208
|
52
52
|
dcicutils/redis_tools.py,sha256=qkcSNMtvqkpvts-Cm9gWhneK523Q_oHwhNUud1be1qk,7055
|
53
53
|
dcicutils/redis_utils.py,sha256=VJ-7g8pOZqR1ZCtdcjKz3-6as2DMUcs1b1zG6wSprH4,6462
|
54
54
|
dcicutils/s3_utils.py,sha256=LauLFQGvZLfpBJ81tYMikjLd3SJRz2R_FrL1n4xSlyI,28868
|
55
|
-
dcicutils/schema_utils.py,sha256=
|
55
|
+
dcicutils/schema_utils.py,sha256=Ky1KCrHYbDR4qd1prHBKJvO8Z_1x1xVUup1SsQsVP24,10002
|
56
56
|
dcicutils/scripts/publish_to_pypi.py,sha256=LFzNHIQK2EXFr88YcfctyA_WKEBFc1ElnSjWrCXedPM,13889
|
57
57
|
dcicutils/scripts/run_license_checker.py,sha256=z2keYnRDZsHQbTeo1XORAXSXNJK5axVzL5LjiNqZ7jE,4184
|
58
58
|
dcicutils/secrets_utils.py,sha256=8dppXAsiHhJzI6NmOcvJV5ldvKkQZzh3Fl-cb8Wm7MI,19745
|
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=OzT6BZoh7LDw3Tw7mjPJ-SscCyCDQjJ_-yFOWV3jOf8,37319
|
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.1b12.dist-info/LICENSE.txt,sha256=qnwSmfnEWMl5l78VPDEzAmEbLVrRqQvfUQiHT0ehrOo,1102
|
70
|
+
dcicutils-8.7.1.1b12.dist-info/METADATA,sha256=TX64_N_gAD4az9l4pcyZDOHOT8ahGQqp9eTA-LQXDCM,3315
|
71
|
+
dcicutils-8.7.1.1b12.dist-info/WHEEL,sha256=7Z8_27uaHI_UZAc4Uox4PpBhQ9Y5_modZXWMxtUi4NU,88
|
72
|
+
dcicutils-8.7.1.1b12.dist-info/entry_points.txt,sha256=8wbw5csMIgBXhkwfgsgJeuFcoUc0WsucUxmOyml2aoA,209
|
73
|
+
dcicutils-8.7.1.1b12.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|