dcicutils 8.8.6__py3-none-any.whl → 8.8.6.1b1__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_utils.py +50 -0
- dcicutils/structured_data.py +9 -3
- {dcicutils-8.8.6.dist-info → dcicutils-8.8.6.1b1.dist-info}/METADATA +1 -1
- {dcicutils-8.8.6.dist-info → dcicutils-8.8.6.1b1.dist-info}/RECORD +7 -7
- {dcicutils-8.8.6.dist-info → dcicutils-8.8.6.1b1.dist-info}/LICENSE.txt +0 -0
- {dcicutils-8.8.6.dist-info → dcicutils-8.8.6.1b1.dist-info}/WHEEL +0 -0
- {dcicutils-8.8.6.dist-info → dcicutils-8.8.6.1b1.dist-info}/entry_points.txt +0 -0
dcicutils/portal_utils.py
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
from collections import deque
|
2
2
|
from functools import lru_cache
|
3
|
+
from dcicutils.function_cache_decorator import function_cache
|
3
4
|
import io
|
4
5
|
import json
|
5
6
|
from pyramid.config import Configurator as PyramidConfigurator
|
@@ -18,6 +19,7 @@ from wsgiref.simple_server import make_server as wsgi_make_server
|
|
18
19
|
from dcicutils.common import APP_SMAHT, OrchestratedApp, ORCHESTRATED_APPS
|
19
20
|
from dcicutils.ff_utils import get_metadata, get_schema, patch_metadata, post_metadata
|
20
21
|
from dcicutils.misc_utils import to_camel_case, VirtualApp
|
22
|
+
from dcicutils.schema_utils import get_identifying_properties
|
21
23
|
from dcicutils.tmpfile_utils import temporary_file
|
22
24
|
|
23
25
|
Portal = Type["Portal"] # Forward type reference for type hints.
|
@@ -441,6 +443,54 @@ class Portal:
|
|
441
443
|
result_kwargs["timeout"] = timeout
|
442
444
|
return result_kwargs
|
443
445
|
|
446
|
+
@function_cache(maxsize=100, serialize_key=True)
|
447
|
+
def get_identifying_paths(self, portal_object: dict, portal_type: Optional[str] = None) -> List[str]:
|
448
|
+
"""
|
449
|
+
Returns the list of the identifying Portal (URL) paths for the given Portal object. Favors any
|
450
|
+
uuid based path and defavors aliases based paths (ala self.get_identifying_property_names);
|
451
|
+
no other ordering defined. Returns empty list of none or otherwise not found.
|
452
|
+
"""
|
453
|
+
results = []
|
454
|
+
if not isinstance(portal_object, dict):
|
455
|
+
return results
|
456
|
+
if not isinstance(portal_type, str) or not portal_type:
|
457
|
+
if not (portal_type := self.get_schema_type(portal_object)):
|
458
|
+
return results
|
459
|
+
for identifying_property in self.get_identifying_property_names(portal_type):
|
460
|
+
if identifying_value := portal_object.get(identifying_property):
|
461
|
+
if isinstance(identifying_value, list):
|
462
|
+
for identifying_value_item in identifying_value:
|
463
|
+
results.append(f"/{portal_type}/{identifying_value_item}")
|
464
|
+
elif identifying_property == "uuid":
|
465
|
+
results.append(f"/{identifying_value}")
|
466
|
+
else:
|
467
|
+
results.append(f"/{portal_type}/{identifying_value}")
|
468
|
+
return results
|
469
|
+
|
470
|
+
@function_cache(maxsize=100, serialize_key=True)
|
471
|
+
def get_identifying_property_names(self, schema: Union[str, dict]) -> List[str]:
|
472
|
+
"""
|
473
|
+
Returns the list of identifying property names for the given Portal schema, which may
|
474
|
+
be either a schema name or a schema object; empty list of none or otherwise not found.
|
475
|
+
"""
|
476
|
+
results = []
|
477
|
+
if isinstance(schema, str):
|
478
|
+
try:
|
479
|
+
if not (schema := self.get_schema(schema)):
|
480
|
+
return results
|
481
|
+
except Exception:
|
482
|
+
return results
|
483
|
+
elif not isinstance(schema, dict):
|
484
|
+
return results
|
485
|
+
if not (identifying_properties := get_identifying_properties(schema)):
|
486
|
+
return results
|
487
|
+
identifying_properties = [*identifying_properties]
|
488
|
+
for favored_identifying_property in reversed(["uuid", "identifier"]):
|
489
|
+
if favored_identifying_property in identifying_properties:
|
490
|
+
identifying_properties.remove(favored_identifying_property)
|
491
|
+
identifying_properties.insert(0, favored_identifying_property)
|
492
|
+
return identifying_properties
|
493
|
+
|
444
494
|
@staticmethod
|
445
495
|
def _default_keys_file(app: Optional[str], env: Optional[str], server: Optional[str]) -> Optional[str]:
|
446
496
|
def infer_app_from_env(env: str) -> Optional[str]: # noqa
|
dcicutils/structured_data.py
CHANGED
@@ -56,7 +56,7 @@ class StructuredDataSet:
|
|
56
56
|
remove_empty_objects_from_lists: bool = True,
|
57
57
|
ref_lookup_strategy: Optional[Callable] = None,
|
58
58
|
ref_lookup_nocache: bool = False,
|
59
|
-
norefs: bool = False,
|
59
|
+
norefs: bool = False, merge: bool = False,
|
60
60
|
progress: Optional[Callable] = None,
|
61
61
|
debug_sleep: Optional[str] = None) -> None:
|
62
62
|
self._progress = progress if callable(progress) else None
|
@@ -75,6 +75,7 @@ class StructuredDataSet:
|
|
75
75
|
self._nrows = 0
|
76
76
|
self._autoadd_properties = autoadd if isinstance(autoadd, dict) and autoadd else None
|
77
77
|
self._norefs = True if norefs is True else False
|
78
|
+
self._merge = True if merge is True else False
|
78
79
|
self._debug_sleep = None
|
79
80
|
if debug_sleep:
|
80
81
|
try:
|
@@ -98,13 +99,13 @@ class StructuredDataSet:
|
|
98
99
|
remove_empty_objects_from_lists: bool = True,
|
99
100
|
ref_lookup_strategy: Optional[Callable] = None,
|
100
101
|
ref_lookup_nocache: bool = False,
|
101
|
-
norefs: bool = False,
|
102
|
+
norefs: bool = False, merge: bool = False,
|
102
103
|
progress: Optional[Callable] = None,
|
103
104
|
debug_sleep: Optional[str] = None) -> StructuredDataSet:
|
104
105
|
return StructuredDataSet(file=file, portal=portal, schemas=schemas, autoadd=autoadd, order=order, prune=prune,
|
105
106
|
remove_empty_objects_from_lists=remove_empty_objects_from_lists,
|
106
107
|
ref_lookup_strategy=ref_lookup_strategy, ref_lookup_nocache=ref_lookup_nocache,
|
107
|
-
norefs=norefs, progress=progress, debug_sleep=debug_sleep)
|
108
|
+
norefs=norefs, merge=merge, progress=progress, debug_sleep=debug_sleep)
|
108
109
|
|
109
110
|
def validate(self, force: bool = False) -> None:
|
110
111
|
def data_without_deleted_properties(data: dict) -> dict:
|
@@ -383,6 +384,11 @@ class StructuredDataSet:
|
|
383
384
|
structured_row_template.set_value(structured_row, column_name, value, reader.file, reader.row_number)
|
384
385
|
if self._autoadd_properties:
|
385
386
|
self._add_properties(structured_row, self._autoadd_properties, schema)
|
387
|
+
# New merge functionality (2024-05-25).
|
388
|
+
if self._merge:
|
389
|
+
for identifying_path in self.get_identifying_paths(self._portal, structured_row, type_name):
|
390
|
+
if existing_portal_object := self._portal.get_metadata(identifying_path):
|
391
|
+
structured_row = merge_objects(existing_portal_object, structured_row)
|
386
392
|
if (prune_error := self._prune_structured_row(structured_row)) is not None:
|
387
393
|
self._note_error({"src": create_dict(type=schema_name, row=reader.row_number),
|
388
394
|
"error": prune_error}, "validation")
|
@@ -48,7 +48,7 @@ dcicutils/misc_utils.py,sha256=zHwsxxEn24muLBP7mDvMa8I9VdMejwW8HMuCL5xbhhw,10769
|
|
48
48
|
dcicutils/obfuscation_utils.py,sha256=fo2jOmDRC6xWpYX49u80bVNisqRRoPskFNX3ymFAmjw,5963
|
49
49
|
dcicutils/opensearch_utils.py,sha256=V2exmFYW8Xl2_pGFixF4I2Cc549Opwe4PhFi5twC0M8,1017
|
50
50
|
dcicutils/portal_object_utils.py,sha256=gDXRgPsRvqCFwbC8WatsuflAxNiigOnqr0Hi93k3AgE,15422
|
51
|
-
dcicutils/portal_utils.py,sha256=
|
51
|
+
dcicutils/portal_utils.py,sha256=_uLdB-ulmFqmClA_Dkpxe4gfEfzSMJSu4yDmtpmqXwQ,33402
|
52
52
|
dcicutils/progress_bar.py,sha256=UT7lxb-rVF_gp4yjY2Tg4eun1naaH__hB4_v3O85bcE,19468
|
53
53
|
dcicutils/project_utils.py,sha256=qPdCaFmWUVBJw4rw342iUytwdQC0P-XKpK4mhyIulMM,31250
|
54
54
|
dcicutils/qa_checkers.py,sha256=cdXjeL0jCDFDLT8VR8Px78aS10hwNISOO5G_Zv2TZ6M,20534
|
@@ -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=
|
67
|
+
dcicutils/structured_data.py,sha256=z0QMgbFafJWoOUMwJJDVufgeT7r7fTTasx1ry5axMVM,63546
|
68
68
|
dcicutils/submitr/progress_constants.py,sha256=5bxyX77ql8qEJearfHEvsvXl7D0GuUODW0T65mbRmnE,2895
|
69
69
|
dcicutils/submitr/ref_lookup_strategy.py,sha256=Js2cVznTmgjciLWBPLCvMiwLIHXjDn3jww-gJPjYuFw,3467
|
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.dist-info/LICENSE.txt,sha256=qnwSmfnEWMl5l78VPDEzAmEbLVrRqQvfUQiHT0ehrOo,1102
|
77
|
-
dcicutils-8.8.6.dist-info/METADATA,sha256=
|
78
|
-
dcicutils-8.8.6.dist-info/WHEEL,sha256=7Z8_27uaHI_UZAc4Uox4PpBhQ9Y5_modZXWMxtUi4NU,88
|
79
|
-
dcicutils-8.8.6.dist-info/entry_points.txt,sha256=51Q4F_2V10L0282W7HFjP4jdzW4K8lnWDARJQVFy_hw,270
|
80
|
-
dcicutils-8.8.6.dist-info/RECORD,,
|
76
|
+
dcicutils-8.8.6.1b1.dist-info/LICENSE.txt,sha256=qnwSmfnEWMl5l78VPDEzAmEbLVrRqQvfUQiHT0ehrOo,1102
|
77
|
+
dcicutils-8.8.6.1b1.dist-info/METADATA,sha256=5iidFphml1M_LwEmfPJdZnLcaSqT2FflV9Ld2JmeCWk,3439
|
78
|
+
dcicutils-8.8.6.1b1.dist-info/WHEEL,sha256=7Z8_27uaHI_UZAc4Uox4PpBhQ9Y5_modZXWMxtUi4NU,88
|
79
|
+
dcicutils-8.8.6.1b1.dist-info/entry_points.txt,sha256=51Q4F_2V10L0282W7HFjP4jdzW4K8lnWDARJQVFy_hw,270
|
80
|
+
dcicutils-8.8.6.1b1.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|