dcicutils 8.4.0.1b11__py3-none-any.whl → 8.4.0.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.
@@ -0,0 +1,267 @@
1
+ from collections import deque
2
+ from pyramid.paster import get_app
3
+ from pyramid.router import Router
4
+ import re
5
+ import requests
6
+ from requests.models import Response as RequestResponse
7
+ from typing import Optional, Type, Union
8
+ from webtest.app import TestApp, TestResponse
9
+ from dcicutils.common import OrchestratedApp, APP_CGAP, APP_FOURFRONT, APP_SMAHT, ORCHESTRATED_APPS
10
+ from dcicutils.creds_utils import CGAPKeyManager, FourfrontKeyManager, SMaHTKeyManager
11
+ from dcicutils.ff_utils import get_metadata, get_schema, patch_metadata, post_metadata
12
+ from dcicutils.misc_utils import to_camel_case, VirtualApp
13
+ from dcicutils.zip_utils import temporary_file
14
+
15
+ Portal = Type["Portal"] # Forward type reference for type hints.
16
+ FILE_SCHEMA_NAME = "File"
17
+
18
+
19
+ class Portal:
20
+
21
+ def __init__(self,
22
+ arg: Optional[Union[VirtualApp, TestApp, Router, Portal, dict, tuple, str]] = None,
23
+ env: Optional[str] = None, app: Optional[OrchestratedApp] = None, server: Optional[str] = None,
24
+ key: Optional[Union[dict, tuple]] = None,
25
+ vapp: Optional[Union[VirtualApp, TestApp, Router, Portal, str]] = None,
26
+ portal: Optional[Union[VirtualApp, TestApp, Router, Portal, str]] = None) -> Portal:
27
+ if vapp and not portal:
28
+ portal = vapp
29
+ if ((isinstance(arg, (VirtualApp, TestApp, Router, Portal)) or
30
+ isinstance(arg, str) and arg.endswith(".ini")) and not portal):
31
+ portal = arg
32
+ elif isinstance(arg, str) and not env:
33
+ env = arg
34
+ elif (isinstance(arg, dict) or isinstance(arg, tuple)) and not key:
35
+ key = arg
36
+ if not app and env:
37
+ if env.startswith(APP_SMAHT):
38
+ app = APP_SMAHT
39
+ elif env.startswith(APP_CGAP):
40
+ app = APP_CGAP
41
+ elif env.startswith(APP_FOURFRONT):
42
+ app = APP_FOURFRONT
43
+ if isinstance(portal, Portal):
44
+ self._vapp = portal._vapp
45
+ self._env = portal._env
46
+ self._app = portal._app
47
+ self._server = portal._server
48
+ self._key = portal._key
49
+ self._key_pair = portal._key_pair
50
+ self._key_file = portal._key_file
51
+ return
52
+ self._vapp = None
53
+ self._env = env
54
+ self._app = app
55
+ self._server = server
56
+ self._key = None
57
+ self._key_pair = None
58
+ self._key_file = None
59
+ if isinstance(portal, (VirtualApp, TestApp)):
60
+ self._vapp = portal
61
+ elif isinstance(portal, (Router, str)):
62
+ self._vapp = Portal._create_testapp(portal)
63
+ elif isinstance(key, dict):
64
+ self._key = key
65
+ self._key_pair = (key.get("key"), key.get("secret")) if key else None
66
+ if key_server := key.get("server"):
67
+ self._server = key_server
68
+ elif isinstance(key, tuple) and len(key) >= 2:
69
+ self._key = {"key": key[0], "secret": key[1]}
70
+ self._key_pair = key
71
+ elif isinstance(env, str):
72
+ key_managers = {APP_CGAP: CGAPKeyManager, APP_FOURFRONT: FourfrontKeyManager, APP_SMAHT: SMaHTKeyManager}
73
+ if not (key_manager := key_managers.get(self._app)) or not (key_manager := key_manager()):
74
+ raise Exception(f"Invalid app name: {self._app} (valid: {', '.join(ORCHESTRATED_APPS)}).")
75
+ if isinstance(env, str):
76
+ self._key = key_manager.get_keydict_for_env(env)
77
+ if key_server := self._key.get("server"):
78
+ self._server = key_server
79
+ elif isinstance(self._server, str):
80
+ self._key = key_manager.get_keydict_for_server(self._server)
81
+ self._key_pair = key_manager.keydict_to_keypair(self._key) if self._key else None
82
+ self._key_file = key_manager.keys_file
83
+
84
+ @property
85
+ def env(self):
86
+ return self._env
87
+
88
+ @property
89
+ def app(self):
90
+ return self._app
91
+
92
+ @property
93
+ def server(self):
94
+ return self._server
95
+
96
+ @property
97
+ def key(self):
98
+ return self._key
99
+
100
+ @property
101
+ def key_pair(self):
102
+ return self._key_pair
103
+
104
+ @property
105
+ def key_file(self):
106
+ return self._key_file
107
+
108
+ @property
109
+ def vapp(self):
110
+ return self._vapp
111
+
112
+ def get_metadata(self, object_id: str) -> Optional[dict]:
113
+ return get_metadata(obj_id=object_id, vapp=self._vapp, key=self._key)
114
+
115
+ def patch_metadata(self, object_id: str, data: str) -> Optional[dict]:
116
+ if self._key:
117
+ return patch_metadata(obj_id=object_id, patch_item=data, key=self._key)
118
+ return self.patch(f"/{object_id}", data)
119
+
120
+ def post_metadata(self, object_type: str, data: str) -> Optional[dict]:
121
+ if self._key:
122
+ return post_metadata(schema_name=object_type, post_item=data, key=self._key)
123
+ return self.post(f"/{object_type}", data)
124
+
125
+ def get(self, uri: str, follow: bool = True, **kwargs) -> Optional[Union[RequestResponse, TestResponse]]:
126
+ if isinstance(self._vapp, (VirtualApp, TestApp)):
127
+ response = self._vapp.get(self._uri(uri), **self._kwargs(**kwargs))
128
+ if response and response.status_code in [301, 302, 303, 307, 308] and follow:
129
+ response = response.follow()
130
+ return self._response(response)
131
+ return requests.get(self._uri(uri), allow_redirects=follow, **self._kwargs(**kwargs))
132
+
133
+ def patch(self, uri: str, data: Optional[dict] = None,
134
+ json: Optional[dict] = None, **kwargs) -> Optional[Union[RequestResponse, TestResponse]]:
135
+ if isinstance(self._vapp, (VirtualApp, TestApp)):
136
+ return self._vapp.patch_json(self._uri(uri), json or data, **self._kwargs(**kwargs))
137
+ return requests.patch(self._uri(uri), json=json or data, **self._kwargs(**kwargs))
138
+
139
+ def post(self, uri: str, data: Optional[dict] = None, json: Optional[dict] = None,
140
+ files: Optional[dict] = None, **kwargs) -> Optional[Union[RequestResponse, TestResponse]]:
141
+ if isinstance(self._vapp, (VirtualApp, TestApp)):
142
+ if files:
143
+ return self._vapp.post(self._uri(uri), json or data, upload_files=files, **self._kwargs(**kwargs))
144
+ else:
145
+ return self._vapp.post_json(self._uri(uri), json or data, upload_files=files, **self._kwargs(**kwargs))
146
+ return requests.post(self._uri(uri), json=json or data, files=files, **self._kwargs(**kwargs))
147
+
148
+ def get_schema(self, schema_name: str) -> Optional[dict]:
149
+ return get_schema(self.schema_name(schema_name), portal_vapp=self._vapp, key=self._key)
150
+
151
+ def get_schemas(self) -> dict:
152
+ return self.get("/profiles/").json()
153
+
154
+ @staticmethod
155
+ def schema_name(name: str) -> str:
156
+ return to_camel_case(name)
157
+
158
+ def is_file_schema(self, schema_name: str) -> bool:
159
+ if super_type_map := self.get_schemas_super_type_map():
160
+ if file_super_type := super_type_map.get(FILE_SCHEMA_NAME):
161
+ return self.schema_name(schema_name) in file_super_type
162
+ return False
163
+
164
+ def get_schemas_super_type_map(self) -> dict:
165
+ """
166
+ Returns the "super type map" for all of the known schemas (via /profiles).
167
+ This is a dictionary of all types which have (one or more) sub-types whose value is
168
+ an array of all of those sub-types (direct and all descendents), in breadth first order.
169
+ """
170
+ def breadth_first(super_type_map: dict, super_type_name: str) -> dict:
171
+ result = []
172
+ queue = deque(super_type_map.get(super_type_name, []))
173
+ while queue:
174
+ result.append(sub_type_name := queue.popleft())
175
+ if sub_type_name in super_type_map:
176
+ queue.extend(super_type_map[sub_type_name])
177
+ return result
178
+ if not (schemas := self.get_schemas()):
179
+ return {}
180
+ super_type_map = {}
181
+ for type_name in schemas:
182
+ if super_type_name := schemas[type_name].get("rdfs:subClassOf"):
183
+ super_type_name = super_type_name.replace("/profiles/", "").replace(".json", "")
184
+ if super_type_name != "Item":
185
+ if not super_type_map.get(super_type_name):
186
+ super_type_map[super_type_name] = [type_name]
187
+ elif type_name not in super_type_map[super_type_name]:
188
+ super_type_map[super_type_name].append(type_name)
189
+ super_type_map_flattened = {}
190
+ for super_type_name in super_type_map:
191
+ super_type_map_flattened[super_type_name] = breadth_first(super_type_map, super_type_name)
192
+ return super_type_map_flattened
193
+
194
+ def _uri(self, uri: str) -> str:
195
+ if not isinstance(uri, str) or not uri:
196
+ return "/"
197
+ if uri.lower().startswith("http://") or uri.lower().startswith("https://"):
198
+ return uri
199
+ uri = re.sub(r"/+", "/", uri)
200
+ return (self._server + ("/" if uri.startswith("/") else "") + uri) if self._server else uri
201
+
202
+ def _kwargs(self, **kwargs) -> dict:
203
+ result_kwargs = {"headers":
204
+ kwargs.get("headers", {"Content-type": "application/json", "Accept": "application/json"})}
205
+ if self._key_pair:
206
+ result_kwargs["auth"] = self._key_pair
207
+ if isinstance(timeout := kwargs.get("timeout"), int):
208
+ result_kwargs["timeout"] = timeout
209
+ return result_kwargs
210
+
211
+ def _response(self, response) -> Optional[RequestResponse]:
212
+ if response and isinstance(getattr(response.__class__, "json"), property):
213
+ class RequestResponseWrapper: # For consistency change json property to method.
214
+ def __init__(self, response, **kwargs):
215
+ super().__init__(**kwargs)
216
+ self._response = response
217
+ def __getattr__(self, attr): # noqa
218
+ return getattr(self._response, attr)
219
+ def json(self): # noqa
220
+ return self._response.json
221
+ response = RequestResponseWrapper(response)
222
+ return response
223
+
224
+ @staticmethod
225
+ def create_for_testing(ini_file: Optional[str] = None) -> Portal:
226
+ if isinstance(ini_file, str):
227
+ return Portal(Portal._create_testapp(ini_file))
228
+ minimal_ini_for_unit_testing = "[app:app]\nuse = egg:encoded\nsqlalchemy.url = postgresql://dummy\n"
229
+ with temporary_file(content=minimal_ini_for_unit_testing, suffix=".ini") as ini_file:
230
+ return Portal(Portal._create_testapp(ini_file))
231
+
232
+ @staticmethod
233
+ def create_for_testing_local(ini_file: Optional[str] = None) -> Portal:
234
+ if isinstance(ini_file, str) and ini_file:
235
+ return Portal(Portal._create_testapp(ini_file))
236
+ minimal_ini_for_testing_local = "\n".join([
237
+ "[app:app]\nuse = egg:encoded\nfile_upload_bucket = dummy",
238
+ "sqlalchemy.url = postgresql://postgres@localhost:5441/postgres?host=/tmp/snovault/pgdata",
239
+ "multiauth.groupfinder = encoded.authorization.smaht_groupfinder",
240
+ "multiauth.policies = auth0 session remoteuser accesskey",
241
+ "multiauth.policy.session.namespace = mailto",
242
+ "multiauth.policy.session.use = encoded.authentication.NamespacedAuthenticationPolicy",
243
+ "multiauth.policy.session.base = pyramid.authentication.SessionAuthenticationPolicy",
244
+ "multiauth.policy.remoteuser.namespace = remoteuser",
245
+ "multiauth.policy.remoteuser.use = encoded.authentication.NamespacedAuthenticationPolicy",
246
+ "multiauth.policy.remoteuser.base = pyramid.authentication.RemoteUserAuthenticationPolicy",
247
+ "multiauth.policy.accesskey.namespace = accesskey",
248
+ "multiauth.policy.accesskey.use = encoded.authentication.NamespacedAuthenticationPolicy",
249
+ "multiauth.policy.accesskey.base = encoded.authentication.BasicAuthAuthenticationPolicy",
250
+ "multiauth.policy.accesskey.check = encoded.authentication.basic_auth_check",
251
+ "multiauth.policy.auth0.use = encoded.authentication.NamespacedAuthenticationPolicy",
252
+ "multiauth.policy.auth0.namespace = auth0",
253
+ "multiauth.policy.auth0.base = encoded.authentication.Auth0AuthenticationPolicy"
254
+ ])
255
+ with temporary_file(content=minimal_ini_for_testing_local, suffix=".ini") as minimal_ini_file:
256
+ return Portal(Portal._create_testapp(minimal_ini_file))
257
+
258
+ @staticmethod
259
+ def _create_testapp(value: Union[str, Router, TestApp] = "development.ini") -> TestApp:
260
+ """
261
+ Creates and returns a TestApp. Refactored out of above loadxl code to consolidate at a
262
+ single point; also for use by the generate_local_access_key and view_local_object scripts.
263
+ """
264
+ if isinstance(value, TestApp):
265
+ return value
266
+ app = value if isinstance(value, Router) else get_app(value, "app")
267
+ return TestApp(app, {"HTTP_ACCEPT": "application/json", "REMOTE_USER": "TEST"})
@@ -1,24 +1,19 @@
1
- from collections import deque
2
1
  import copy
3
2
  from functools import lru_cache
4
3
  import json
5
4
  from jsonschema import Draft7Validator as SchemaValidator
6
5
  import os
7
- from pyramid.paster import get_app
8
6
  from pyramid.router import Router
9
7
  import re
10
- import requests
11
- from requests.models import Response as RequestResponse
12
8
  import sys
13
9
  from typing import Any, Callable, List, Optional, Tuple, Type, Union
14
- from webtest.app import TestApp, TestResponse
15
- from dcicutils.common import OrchestratedApp, APP_CGAP, APP_FOURFRONT, APP_SMAHT, ORCHESTRATED_APPS
16
- from dcicutils.creds_utils import CGAPKeyManager, FourfrontKeyManager, SMaHTKeyManager
10
+ from webtest.app import TestApp
11
+ from dcicutils.common import OrchestratedApp
17
12
  from dcicutils.data_readers import CsvReader, Excel, RowReader
18
- from dcicutils.ff_utils import get_metadata, get_schema, patch_metadata, post_metadata
19
13
  from dcicutils.misc_utils import (create_object, load_json_if, merge_objects, remove_empty_properties, right_trim,
20
- split_string, to_boolean, to_camel_case, to_enum, to_float, to_integer, VirtualApp)
21
- from dcicutils.zip_utils import temporary_file, unpack_gz_file_to_temporary_file, unpack_files
14
+ split_string, to_boolean, to_enum, to_float, to_integer, VirtualApp)
15
+ from dcicutils.portal_utils import Portal as PortalBase
16
+ from dcicutils.zip_utils import unpack_gz_file_to_temporary_file, unpack_files
22
17
 
23
18
 
24
19
  # Classes/functions to parse a CSV or Excel Spreadsheet into structured data, using a specialized
@@ -36,12 +31,10 @@ ARRAY_VALUE_DELIMITER_ESCAPE_CHAR = "\\"
36
31
  ARRAY_NAME_SUFFIX_CHAR = "#"
37
32
  ARRAY_NAME_SUFFIX_REGEX = re.compile(rf"{ARRAY_NAME_SUFFIX_CHAR}\d+")
38
33
  DOTTED_NAME_DELIMITER_CHAR = "."
39
- FILE_SCHEMA_NAME = "File"
40
34
  FILE_SCHEMA_NAME_PROPERTY = "filename"
41
35
 
42
36
  # Forward type references for type hints.
43
37
  Portal = Type["Portal"]
44
- PortalBase = Type["PortalBase"]
45
38
  Schema = Type["Schema"]
46
39
  StructuredDataSet = Type["StructuredDataSet"]
47
40
 
@@ -526,7 +519,7 @@ class Schema:
526
519
  @staticmethod
527
520
  def type_name(value: str) -> str: # File or other name.
528
521
  name = os.path.basename(value).replace(" ", "") if isinstance(value, str) else ""
529
- return to_camel_case(name[0:dot] if (dot := name.rfind(".")) > 0 else name)
522
+ return PortalBase.schema_name(name[0:dot] if (dot := name.rfind(".")) > 0 else name)
530
523
 
531
524
  @staticmethod
532
525
  def array_indices(name: str) -> Tuple[Optional[str], Optional[List[int]]]:
@@ -540,211 +533,15 @@ class Schema:
540
533
  return (name, indices) if indices else (None, None)
541
534
 
542
535
 
543
- class PortalBase:
544
-
545
- def __init__(self,
546
- arg: Optional[Union[VirtualApp, TestApp, Router, PortalBase, dict, tuple, str]] = None,
547
- env: Optional[str] = None, app: OrchestratedApp = APP_SMAHT, server: Optional[str] = None,
548
- key: Optional[Union[dict, tuple]] = None,
549
- portal: Optional[Union[VirtualApp, TestApp, Router, PortalBase, str]] = None) -> PortalBase:
550
- if ((isinstance(arg, (VirtualApp, TestApp, Router, PortalBase)) or
551
- isinstance(arg, str) and arg.endswith(".ini")) and not portal):
552
- portal = arg
553
- elif isinstance(arg, str) and not env:
554
- env = arg
555
- elif (isinstance(arg, dict) or isinstance(arg, tuple)) and not key:
556
- key = arg
557
- self._vapp = None
558
- self._key = None
559
- self._key_pair = None
560
- self._key_file = None
561
- self._env = env
562
- self._app = app
563
- self._server = None
564
- if isinstance(portal, PortalBase):
565
- self._vapp = portal._vapp
566
- self._key = portal._key
567
- self._key_pair = portal._key_pair
568
- self._server = portal._server
569
- elif isinstance(portal, (VirtualApp, TestApp)):
570
- self._vapp = portal
571
- elif isinstance(portal, (Router, str)):
572
- self._vapp = PortalBase._create_testapp(portal)
573
- elif isinstance(key, dict):
574
- self._key = key
575
- self._key_pair = (key.get("key"), key.get("secret")) if key else None
576
- self._server = key.get("server")
577
- elif isinstance(key, tuple) and len(key) >= 2:
578
- self._key = {"key": key[0], "secret": key[1]}
579
- self._key_pair = key
580
- elif isinstance(env, str):
581
- key_managers = {APP_CGAP: CGAPKeyManager, APP_FOURFRONT: FourfrontKeyManager, APP_SMAHT: SMaHTKeyManager}
582
- if not (key_manager := key_managers.get(app)) or not (key_manager := key_manager()):
583
- raise Exception(f"Invalid app name: {app} (valid: {', '.join(ORCHESTRATED_APPS)}).")
584
- if isinstance(env, str):
585
- self._key = key_manager.get_keydict_for_env(env)
586
- self._server = self._key.get("server") if self._key else None
587
- elif isinstance(server, str):
588
- self._key = key_manager.get_keydict_for_server(server)
589
- self._server = server
590
- self._key_pair = key_manager.keydict_to_keypair(self._key) if self._key else None
591
- self._key_file = key_manager.keys_file
592
-
593
- @property
594
- def env(self):
595
- return self._env
596
-
597
- @property
598
- def app(self):
599
- return self._app
600
-
601
- @property
602
- def key(self):
603
- return self._key
604
-
605
- @property
606
- def key_pair(self):
607
- return self._key_pair
608
-
609
- @property
610
- def key_file(self):
611
- return self._key_file
612
-
613
- @property
614
- def server(self):
615
- return self._server
616
-
617
- @property
618
- def vapp(self):
619
- return self._vapp
620
-
621
- def get_metadata(self, object_id: str) -> Optional[dict]:
622
- return get_metadata(obj_id=object_id, vapp=self._vapp, key=self._key)
623
-
624
- def patch_metadata(self, object_id: str, data: str) -> Optional[dict]:
625
- if self._key:
626
- return patch_metadata(obj_id=object_id, patch_item=data, key=self._key)
627
- return self.patch(f"/{object_id}", data)
628
-
629
- def post_metadata(self, object_type: str, data: str) -> Optional[dict]:
630
- if self._key:
631
- return post_metadata(schema_name=object_type, post_item=data, key=self._key)
632
- return self.post(f"/{object_type}", data)
633
-
634
- def get(self, uri: str, follow: bool = True, **kwargs) -> Optional[Union[RequestResponse, TestResponse]]:
635
- if isinstance(self._vapp, (VirtualApp, TestApp)):
636
- response = self._vapp.get(self._uri(uri), **self._kwargs(**kwargs))
637
- if response and response.status_code in [301, 302, 303, 307, 308] and follow:
638
- response = response.follow()
639
- return self._response(response)
640
- return requests.get(self._uri(uri), allow_redirects=follow, **self._kwargs(**kwargs))
641
-
642
- def patch(self, uri: str, data: Optional[dict] = None,
643
- json: Optional[dict] = None, **kwargs) -> Optional[Union[RequestResponse, TestResponse]]:
644
- if isinstance(self._vapp, (VirtualApp, TestApp)):
645
- return self._vapp.patch_json(self._uri(uri), json or data, **self._kwargs(**kwargs))
646
- return requests.patch(self._uri(uri), json=json or data, **self._kwargs(**kwargs))
647
-
648
- def post(self, uri: str, data: Optional[dict] = None, json: Optional[dict] = None,
649
- files: Optional[dict] = None, **kwargs) -> Optional[Union[RequestResponse, TestResponse]]:
650
- if isinstance(self._vapp, (VirtualApp, TestApp)):
651
- if files:
652
- return self._vapp.post(self._uri(uri), json or data, upload_files=files, **self._kwargs(**kwargs))
653
- else:
654
- return self._vapp.post_json(self._uri(uri), json or data, upload_files=files, **self._kwargs(**kwargs))
655
- return requests.post(self._uri(uri), json=json or data, files=files, **self._kwargs(**kwargs))
656
-
657
- def get_schema(self, schema_name: str) -> Optional[dict]:
658
- return get_schema(schema_name, portal_vapp=self._vapp, key=self._key)
659
-
660
- def get_schemas(self) -> dict:
661
- return self.get("/profiles/").json()
662
-
663
- def _uri(self, uri: str) -> str:
664
- if not isinstance(uri, str) or not uri:
665
- return "/"
666
- if uri.lower().startswith("http://") or uri.lower().startswith("https://"):
667
- return uri
668
- uri = re.sub(r"/+", "/", uri)
669
- return (self._server + ("/" if uri.startswith("/") else "") + uri) if self._server else uri
670
-
671
- def _kwargs(self, **kwargs) -> dict:
672
- result_kwargs = {"headers":
673
- kwargs.get("headers", {"Content-type": "application/json", "Accept": "application/json"})}
674
- if self._key_pair:
675
- result_kwargs["auth"] = self._key_pair
676
- if isinstance(timeout := kwargs.get("timeout"), int):
677
- result_kwargs["timeout"] = timeout
678
- return result_kwargs
679
-
680
- def _response(self, response) -> Optional[RequestResponse]:
681
- if response and isinstance(getattr(response.__class__, "json"), property):
682
- class RequestResponseWrapper: # For consistency change json property to method.
683
- def __init__(self, response, **kwargs):
684
- super().__init__(**kwargs)
685
- self._response = response
686
- def __getattr__(self, attr): # noqa
687
- return getattr(self._response, attr)
688
- def json(self): # noqa
689
- return self._response.json
690
- response = RequestResponseWrapper(response)
691
- return response
692
-
693
- @staticmethod
694
- def create_for_testing(ini_file: Optional[str] = None) -> PortalBase:
695
- if isinstance(ini_file, str):
696
- return PortalBase(PortalBase._create_testapp(ini_file))
697
- minimal_ini_for_unit_testing = "[app:app]\nuse = egg:encoded\nsqlalchemy.url = postgresql://dummy\n"
698
- with temporary_file(content=minimal_ini_for_unit_testing, suffix=".ini") as ini_file:
699
- return PortalBase(PortalBase._create_testapp(ini_file))
700
-
701
- @staticmethod
702
- def create_for_testing_local(ini_file: Optional[str] = None) -> PortalBase:
703
- if isinstance(ini_file, str) and ini_file:
704
- return PortalBase(PortalBase._create_testapp(ini_file))
705
- minimal_ini_for_testing_local = "\n".join([
706
- "[app:app]\nuse = egg:encoded\nfile_upload_bucket = dummy",
707
- "sqlalchemy.url = postgresql://postgres@localhost:5441/postgres?host=/tmp/snovault/pgdata",
708
- "multiauth.groupfinder = encoded.authorization.smaht_groupfinder",
709
- "multiauth.policies = auth0 session remoteuser accesskey",
710
- "multiauth.policy.session.namespace = mailto",
711
- "multiauth.policy.session.use = encoded.authentication.NamespacedAuthenticationPolicy",
712
- "multiauth.policy.session.base = pyramid.authentication.SessionAuthenticationPolicy",
713
- "multiauth.policy.remoteuser.namespace = remoteuser",
714
- "multiauth.policy.remoteuser.use = encoded.authentication.NamespacedAuthenticationPolicy",
715
- "multiauth.policy.remoteuser.base = pyramid.authentication.RemoteUserAuthenticationPolicy",
716
- "multiauth.policy.accesskey.namespace = accesskey",
717
- "multiauth.policy.accesskey.use = encoded.authentication.NamespacedAuthenticationPolicy",
718
- "multiauth.policy.accesskey.base = encoded.authentication.BasicAuthAuthenticationPolicy",
719
- "multiauth.policy.accesskey.check = encoded.authentication.basic_auth_check",
720
- "multiauth.policy.auth0.use = encoded.authentication.NamespacedAuthenticationPolicy",
721
- "multiauth.policy.auth0.namespace = auth0",
722
- "multiauth.policy.auth0.base = encoded.authentication.Auth0AuthenticationPolicy"
723
- ])
724
- with temporary_file(content=minimal_ini_for_testing_local, suffix=".ini") as minimal_ini_file:
725
- return PortalBase(PortalBase._create_testapp(minimal_ini_file))
726
-
727
- @staticmethod
728
- def _create_testapp(value: Union[str, Router, TestApp] = "development.ini") -> TestApp:
729
- """
730
- Creates and returns a TestApp. Refactored out of above loadxl code to consolidate at a
731
- single point; also for use by the generate_local_access_key and view_local_object scripts.
732
- """
733
- if isinstance(value, TestApp):
734
- return value
735
- app = value if isinstance(value, Router) else get_app(value, "app")
736
- return TestApp(app, {"HTTP_ACCEPT": "application/json", "REMOTE_USER": "TEST"})
737
-
738
-
739
536
  class Portal(PortalBase):
740
537
 
741
538
  def __init__(self,
742
539
  arg: Optional[Union[VirtualApp, TestApp, Router, Portal, dict, tuple, str]] = None,
743
- env: Optional[str] = None, app: OrchestratedApp = APP_SMAHT, server: Optional[str] = None,
540
+ env: Optional[str] = None, app: OrchestratedApp = None, server: Optional[str] = None,
744
541
  key: Optional[Union[dict, tuple]] = None,
745
542
  portal: Optional[Union[VirtualApp, TestApp, Router, Portal, str]] = None,
746
543
  data: Optional[dict] = None, schemas: Optional[List[dict]] = None) -> Optional[Portal]:
747
- super(Portal, self).__init__(arg, env=env, app=app, server=server, key=key, portal=portal)
544
+ super().__init__(arg, env=env, app=app, server=server, key=key, portal=portal)
748
545
  if isinstance(arg, Portal) and not portal:
749
546
  portal = arg
750
547
  if isinstance(portal, Portal):
@@ -757,7 +554,7 @@ class Portal(PortalBase):
757
554
  @lru_cache(maxsize=256)
758
555
  def get_metadata(self, object_name: str) -> Optional[dict]:
759
556
  try:
760
- return super(Portal, self).get_metadata(object_name)
557
+ return super().get_metadata(object_name)
761
558
  except Exception:
762
559
  return None
763
560
 
@@ -772,7 +569,7 @@ class Portal(PortalBase):
772
569
 
773
570
  @lru_cache(maxsize=1)
774
571
  def get_schemas(self) -> dict:
775
- schemas = super(Portal, self).get_schemas()
572
+ schemas = super().get_schemas()
776
573
  if self._schemas:
777
574
  schemas = copy.deepcopy(schemas)
778
575
  for user_specified_schema in self._schemas:
@@ -780,42 +577,9 @@ class Portal(PortalBase):
780
577
  schemas[user_specified_schema["title"]] = user_specified_schema
781
578
  return schemas
782
579
 
783
- def is_file_schema(self, schema_name: str) -> bool:
784
- if super_type_map := self.get_schemas_super_type_map():
785
- if file_super_type := super_type_map.get(FILE_SCHEMA_NAME):
786
- return Schema.type_name(schema_name) in file_super_type
787
- return False
788
-
789
580
  @lru_cache(maxsize=1)
790
581
  def get_schemas_super_type_map(self) -> dict:
791
- """
792
- Returns the "super type map" for all of the known schemas (via /profiles).
793
- This is a dictionary of all types which have (one or more) sub-types whose value is
794
- an array of all of those sub-types (direct and all descendents), in breadth first order.
795
- """
796
- def breadth_first(super_type_map: dict, super_type_name: str) -> dict:
797
- result = []
798
- queue = deque(super_type_map.get(super_type_name, []))
799
- while queue:
800
- result.append(sub_type_name := queue.popleft())
801
- if sub_type_name in super_type_map:
802
- queue.extend(super_type_map[sub_type_name])
803
- return result
804
- if not (schemas := self.get_schemas()):
805
- return {}
806
- super_type_map = {}
807
- for type_name in schemas:
808
- if super_type_name := schemas[type_name].get("rdfs:subClassOf"):
809
- super_type_name = super_type_name.replace("/profiles/", "").replace(".json", "")
810
- if super_type_name != "Item":
811
- if not super_type_map.get(super_type_name):
812
- super_type_map[super_type_name] = [type_name]
813
- elif type_name not in super_type_map[super_type_name]:
814
- super_type_map[super_type_name].append(type_name)
815
- super_type_map_flattened = {}
816
- for super_type_name in super_type_map:
817
- super_type_map_flattened[super_type_name] = breadth_first(super_type_map, super_type_name)
818
- return super_type_map_flattened
582
+ return super().get_schemas_super_type_map()
819
583
 
820
584
  def ref_exists(self, type_name: str, value: str) -> List[str]:
821
585
  resolved = []
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dcicutils
3
- Version: 8.4.0.1b11
3
+ Version: 8.4.0.1b12
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
@@ -43,6 +43,7 @@ dcicutils/log_utils.py,sha256=7pWMc6vyrorUZQf-V-M3YC6zrPgNhuV_fzm9xqTPph0,10883
43
43
  dcicutils/misc_utils.py,sha256=jfyWDrHAlx2REun51i3igEApfEMAsmakRDo2VKUr0LQ,99818
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=s918K2f8ZuMD-2-H2GM6foiGe_YtzgG23xHtYe4gjlk,13021
46
47
  dcicutils/project_utils.py,sha256=qPdCaFmWUVBJw4rw342iUytwdQC0P-XKpK4mhyIulMM,31250
47
48
  dcicutils/qa_checkers.py,sha256=cdXjeL0jCDFDLT8VR8Px78aS10hwNISOO5G_Zv2TZ6M,20534
48
49
  dcicutils/qa_utils.py,sha256=TT0SiJWiuxYvbsIyhK9VO4uV_suxhB6CpuC4qPacCzQ,160208
@@ -55,14 +56,14 @@ dcicutils/secrets_utils.py,sha256=8dppXAsiHhJzI6NmOcvJV5ldvKkQZzh3Fl-cb8Wm7MI,19
55
56
  dcicutils/sheet_utils.py,sha256=VlmzteONW5VF_Q4vo0yA5vesz1ViUah1MZ_yA1rwZ0M,33629
56
57
  dcicutils/snapshot_utils.py,sha256=ymP7PXH6-yEiXAt75w0ldQFciGNqWBClNxC5gfX2FnY,22961
57
58
  dcicutils/ssl_certificate_utils.py,sha256=F0ifz_wnRRN9dfrfsz7aCp4UDLgHEY8LaK7PjnNvrAQ,9707
58
- dcicutils/structured_data.py,sha256=2kbilJVmGPsZh57xEreSEjTYWCjkOvDCO0L0QxWsIxQ,44093
59
+ dcicutils/structured_data.py,sha256=LGfNwJXYC5SHs92HA27XijbFZcCXfOatYVI1oo0tKu4,32120
59
60
  dcicutils/task_utils.py,sha256=MF8ujmTD6-O2AC2gRGPHyGdUrVKgtr8epT5XU8WtNjk,8082
60
61
  dcicutils/trace_utils.py,sha256=g8kwV4ebEy5kXW6oOrEAUsurBcCROvwtZqz9fczsGRE,1769
61
62
  dcicutils/validation_utils.py,sha256=cMZIU2cY98FYtzK52z5WUYck7urH6JcqOuz9jkXpqzg,14797
62
63
  dcicutils/variant_utils.py,sha256=2H9azNx3xAj-MySg-uZ2SFqbWs4kZvf61JnK6b-h4Qw,4343
63
64
  dcicutils/zip_utils.py,sha256=0OXR0aLNwyLIZOzIFTM_5DOun7dxIv6TIZbFiithkO0,3276
64
- dcicutils-8.4.0.1b11.dist-info/LICENSE.txt,sha256=t0_-jIjqxNnymZoNJe-OltRIuuF8qfhN0ATlHyrUJPk,1102
65
- dcicutils-8.4.0.1b11.dist-info/METADATA,sha256=Uxe75Y_H7TDmO4UlOuw_VsaPcC7UEoxpS58zn8EjHQE,3315
66
- dcicutils-8.4.0.1b11.dist-info/WHEEL,sha256=7Z8_27uaHI_UZAc4Uox4PpBhQ9Y5_modZXWMxtUi4NU,88
67
- dcicutils-8.4.0.1b11.dist-info/entry_points.txt,sha256=8wbw5csMIgBXhkwfgsgJeuFcoUc0WsucUxmOyml2aoA,209
68
- dcicutils-8.4.0.1b11.dist-info/RECORD,,
65
+ dcicutils-8.4.0.1b12.dist-info/LICENSE.txt,sha256=t0_-jIjqxNnymZoNJe-OltRIuuF8qfhN0ATlHyrUJPk,1102
66
+ dcicutils-8.4.0.1b12.dist-info/METADATA,sha256=f_Btb9g9ursc6-9DzbsrcbYRUMx4Te9rc2aotcDsphM,3315
67
+ dcicutils-8.4.0.1b12.dist-info/WHEEL,sha256=7Z8_27uaHI_UZAc4Uox4PpBhQ9Y5_modZXWMxtUi4NU,88
68
+ dcicutils-8.4.0.1b12.dist-info/entry_points.txt,sha256=8wbw5csMIgBXhkwfgsgJeuFcoUc0WsucUxmOyml2aoA,209
69
+ dcicutils-8.4.0.1b12.dist-info/RECORD,,