dcicutils 8.4.0.1b10__py3-none-any.whl → 8.4.0.1b12__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of dcicutils might be problematic. Click here for more details.

@@ -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,179 +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, Portal, 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, Portal, str]] = None) -> PortalBase:
550
- if ((isinstance(arg, (VirtualApp, TestApp, Router, Portal)) 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._server = None
561
- if isinstance(portal, Portal):
562
- self._vapp = portal._vapp
563
- self._key = portal._key
564
- self._key_pair = portal._key_pair
565
- self._server = portal._server
566
- elif isinstance(portal, (VirtualApp, TestApp)):
567
- self._vapp = portal
568
- elif isinstance(portal, (Router, str)):
569
- self._vapp = PortalBase._create_testapp(portal)
570
- elif isinstance(key, dict):
571
- self._key = key
572
- self._key_pair = (key.get("key"), key.get("secret")) if key else None
573
- self._server = key.get("server")
574
- elif isinstance(key, tuple) and len(key) >= 2:
575
- self._key = {"key": key[0], "secret": key[1]}
576
- self._key_pair = key
577
- elif isinstance(env, str):
578
- key_managers = {APP_CGAP: CGAPKeyManager, APP_FOURFRONT: FourfrontKeyManager, APP_SMAHT: SMaHTKeyManager}
579
- if not (key_manager := key_managers.get(app)) or not (key_manager := key_manager()):
580
- raise Exception(f"Invalid app name: {app} (valid: {', '.join(ORCHESTRATED_APPS)}).")
581
- if isinstance(env, str):
582
- self._key = key_manager.get_keydict_for_env(env)
583
- self._server = self._key.get("server") if self._key else None
584
- elif isinstance(server, str):
585
- self._key = key_manager.get_keydict_for_server(server)
586
- self._server = server
587
- self._key_pair = key_manager.keydict_to_keypair(self._key) if self._key else None
588
-
589
- def get_metadata(self, object_id: str) -> Optional[dict]:
590
- return get_metadata(obj_id=object_id, vapp=self._vapp, key=self._key)
591
-
592
- def patch_metadata(self, object_id: str, data: str) -> Optional[dict]:
593
- if self._key:
594
- return patch_metadata(obj_id=object_id, patch_item=data, key=self._key)
595
- return self.patch(f"/{object_id}", data)
596
-
597
- def post_metadata(self, object_type: str, data: str) -> Optional[dict]:
598
- if self._key:
599
- return post_metadata(schema_name=object_type, post_item=data, key=self._key)
600
- return self.post(f"/{object_type}", data)
601
-
602
- def get(self, uri: str, follow: bool = True, **kwargs) -> Optional[Union[RequestResponse, TestResponse]]:
603
- if isinstance(self._vapp, (VirtualApp, TestApp)):
604
- response = self._vapp.get(self._uri(uri), **self._kwargs(**kwargs))
605
- if response and response.status_code in [301, 302, 303, 307, 308] and follow:
606
- response = response.follow()
607
- return self._response(response)
608
- return requests.get(self._uri(uri), allow_redirects=follow, **self._kwargs(**kwargs))
609
-
610
- def patch(self, uri: str, data: Optional[dict] = None,
611
- json: Optional[dict] = None, **kwargs) -> Optional[Union[RequestResponse, TestResponse]]:
612
- if isinstance(self._vapp, (VirtualApp, TestApp)):
613
- return self._vapp.patch_json(self._uri(uri), json or data, **self._kwargs(**kwargs))
614
- return requests.patch(self._uri(uri), json=json or data, **self._kwargs(**kwargs))
615
-
616
- def post(self, uri: str, data: Optional[dict] = None, json: Optional[dict] = None,
617
- files: Optional[dict] = None, **kwargs) -> Optional[Union[RequestResponse, TestResponse]]:
618
- if isinstance(self._vapp, (VirtualApp, TestApp)):
619
- if files:
620
- return self._vapp.post(self._uri(uri), json or data, upload_files=files, **self._kwargs(**kwargs))
621
- else:
622
- return self._vapp.post_json(self._uri(uri), json or data, upload_files=files, **self._kwargs(**kwargs))
623
- return requests.post(self._uri(uri), json=json or data, files=files, **self._kwargs(**kwargs))
624
-
625
- def get_schema(self, schema_name: str) -> Optional[dict]:
626
- return get_schema(schema_name, portal_vapp=self._vapp, key=self._key)
627
-
628
- def get_schemas(self) -> dict:
629
- return self.get("/profiles/").json()
630
-
631
- def _uri(self, uri: str) -> str:
632
- if not isinstance(uri, str) or not uri:
633
- return "/"
634
- if uri.lower().startswith("http://") or uri.lower().startswith("https://"):
635
- return uri
636
- uri = re.sub(r"/+", "/", uri)
637
- return (self._server + ("/" if uri.startswith("/") else "") + uri) if self._server else uri
638
-
639
- def _kwargs(self, **kwargs) -> dict:
640
- result_kwargs = {"headers":
641
- kwargs.get("headers", {"Content-type": "application/json", "Accept": "application/json"})}
642
- if self._key_pair:
643
- result_kwargs["auth"] = self._key_pair
644
- if isinstance(timeout := kwargs.get("timeout"), int):
645
- result_kwargs["timeout"] = timeout
646
- return result_kwargs
647
-
648
- def _response(self, response) -> Optional[RequestResponse]:
649
- if response and isinstance(getattr(response.__class__, "json"), property):
650
- class RequestResponseWrapper: # For consistency change json property to method.
651
- def __init__(self, response, **kwargs):
652
- super().__init__(**kwargs)
653
- self._response = response
654
- def __getattr__(self, attr): # noqa
655
- return getattr(self._response, attr)
656
- def json(self): # noqa
657
- return self._response.json
658
- response = RequestResponseWrapper(response)
659
- return response
660
-
661
- @staticmethod
662
- def create_for_testing(ini_file: Optional[str] = None) -> PortalBase:
663
- if isinstance(ini_file, str):
664
- return Portal(Portal._create_testapp(ini_file))
665
- minimal_ini_for_unit_testing = "[app:app]\nuse = egg:encoded\nsqlalchemy.url = postgresql://dummy\n"
666
- with temporary_file(content=minimal_ini_for_unit_testing, suffix=".ini") as ini_file:
667
- return Portal(Portal._create_testapp(ini_file))
668
-
669
- @staticmethod
670
- def create_for_testing_local(ini_file: Optional[str] = None) -> Portal:
671
- if isinstance(ini_file, str) and ini_file:
672
- return Portal(Portal._create_testapp(ini_file))
673
- minimal_ini_for_testing_local = "\n".join([
674
- "[app:app]\nuse = egg:encoded\nfile_upload_bucket = dummy",
675
- "sqlalchemy.url = postgresql://postgres@localhost:5441/postgres?host=/tmp/snovault/pgdata",
676
- "multiauth.groupfinder = encoded.authorization.smaht_groupfinder",
677
- "multiauth.policies = auth0 session remoteuser accesskey",
678
- "multiauth.policy.session.namespace = mailto",
679
- "multiauth.policy.session.use = encoded.authentication.NamespacedAuthenticationPolicy",
680
- "multiauth.policy.session.base = pyramid.authentication.SessionAuthenticationPolicy",
681
- "multiauth.policy.remoteuser.namespace = remoteuser",
682
- "multiauth.policy.remoteuser.use = encoded.authentication.NamespacedAuthenticationPolicy",
683
- "multiauth.policy.remoteuser.base = pyramid.authentication.RemoteUserAuthenticationPolicy",
684
- "multiauth.policy.accesskey.namespace = accesskey",
685
- "multiauth.policy.accesskey.use = encoded.authentication.NamespacedAuthenticationPolicy",
686
- "multiauth.policy.accesskey.base = encoded.authentication.BasicAuthAuthenticationPolicy",
687
- "multiauth.policy.accesskey.check = encoded.authentication.basic_auth_check",
688
- "multiauth.policy.auth0.use = encoded.authentication.NamespacedAuthenticationPolicy",
689
- "multiauth.policy.auth0.namespace = auth0",
690
- "multiauth.policy.auth0.base = encoded.authentication.Auth0AuthenticationPolicy"
691
- ])
692
- with temporary_file(content=minimal_ini_for_testing_local, suffix=".ini") as minimal_ini_file:
693
- return Portal(Portal._create_testapp(minimal_ini_file))
694
-
695
- @staticmethod
696
- def _create_testapp(value: Union[str, Router, TestApp] = "development.ini") -> TestApp:
697
- """
698
- Creates and returns a TestApp. Refactored out of above loadxl code to consolidate at a
699
- single point; also for use by the generate_local_access_key and view_local_object scripts.
700
- """
701
- if isinstance(value, TestApp):
702
- return value
703
- app = value if isinstance(value, Router) else get_app(value, "app")
704
- return TestApp(app, {"HTTP_ACCEPT": "application/json", "REMOTE_USER": "TEST"})
705
-
706
-
707
536
  class Portal(PortalBase):
708
537
 
709
538
  def __init__(self,
710
539
  arg: Optional[Union[VirtualApp, TestApp, Router, Portal, dict, tuple, str]] = None,
711
- env: Optional[str] = None, app: OrchestratedApp = APP_SMAHT, server: Optional[str] = None,
540
+ env: Optional[str] = None, app: OrchestratedApp = None, server: Optional[str] = None,
712
541
  key: Optional[Union[dict, tuple]] = None,
713
542
  portal: Optional[Union[VirtualApp, TestApp, Router, Portal, str]] = None,
714
543
  data: Optional[dict] = None, schemas: Optional[List[dict]] = None) -> Optional[Portal]:
715
- 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)
716
545
  if isinstance(arg, Portal) and not portal:
717
546
  portal = arg
718
547
  if isinstance(portal, Portal):
@@ -725,7 +554,7 @@ class Portal(PortalBase):
725
554
  @lru_cache(maxsize=256)
726
555
  def get_metadata(self, object_name: str) -> Optional[dict]:
727
556
  try:
728
- return super(Portal, self).get_metadata(object_name)
557
+ return super().get_metadata(object_name)
729
558
  except Exception:
730
559
  return None
731
560
 
@@ -740,7 +569,7 @@ class Portal(PortalBase):
740
569
 
741
570
  @lru_cache(maxsize=1)
742
571
  def get_schemas(self) -> dict:
743
- schemas = super(Portal, self).get_schemas()
572
+ schemas = super().get_schemas()
744
573
  if self._schemas:
745
574
  schemas = copy.deepcopy(schemas)
746
575
  for user_specified_schema in self._schemas:
@@ -748,42 +577,9 @@ class Portal(PortalBase):
748
577
  schemas[user_specified_schema["title"]] = user_specified_schema
749
578
  return schemas
750
579
 
751
- def is_file_schema(self, schema_name: str) -> bool:
752
- if super_type_map := self.get_schemas_super_type_map():
753
- if file_super_type := super_type_map.get(FILE_SCHEMA_NAME):
754
- return Schema.type_name(schema_name) in file_super_type
755
- return False
756
-
757
580
  @lru_cache(maxsize=1)
758
581
  def get_schemas_super_type_map(self) -> dict:
759
- """
760
- Returns the "super type map" for all of the known schemas (via /profiles).
761
- This is a dictionary of all types which have (one or more) sub-types whose value is
762
- an array of all of those sub-types (direct and all descendents), in breadth first order.
763
- """
764
- def breadth_first(super_type_map: dict, super_type_name: str) -> dict:
765
- result = []
766
- queue = deque(super_type_map.get(super_type_name, []))
767
- while queue:
768
- result.append(sub_type_name := queue.popleft())
769
- if sub_type_name in super_type_map:
770
- queue.extend(super_type_map[sub_type_name])
771
- return result
772
- if not (schemas := self.get_schemas()):
773
- return {}
774
- super_type_map = {}
775
- for type_name in schemas:
776
- if super_type_name := schemas[type_name].get("rdfs:subClassOf"):
777
- super_type_name = super_type_name.replace("/profiles/", "").replace(".json", "")
778
- if super_type_name != "Item":
779
- if not super_type_map.get(super_type_name):
780
- super_type_map[super_type_name] = [type_name]
781
- elif type_name not in super_type_map[super_type_name]:
782
- super_type_map[super_type_name].append(type_name)
783
- super_type_map_flattened = {}
784
- for super_type_name in super_type_map:
785
- super_type_map_flattened[super_type_name] = breadth_first(super_type_map, super_type_name)
786
- return super_type_map_flattened
582
+ return super().get_schemas_super_type_map()
787
583
 
788
584
  def ref_exists(self, type_name: str, value: str) -> List[str]:
789
585
  resolved = []
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dcicutils
3
- Version: 8.4.0.1b10
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=Jw2FODz3DS5F3lnR3cyV6DkjaivVmnsDHwANkR6kA3c,43471
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.1b10.dist-info/LICENSE.txt,sha256=t0_-jIjqxNnymZoNJe-OltRIuuF8qfhN0ATlHyrUJPk,1102
65
- dcicutils-8.4.0.1b10.dist-info/METADATA,sha256=uaZJfbEP8d9cMeKPfWDnIwgSpUtBvLgOs09P_o4SSzQ,3315
66
- dcicutils-8.4.0.1b10.dist-info/WHEEL,sha256=7Z8_27uaHI_UZAc4Uox4PpBhQ9Y5_modZXWMxtUi4NU,88
67
- dcicutils-8.4.0.1b10.dist-info/entry_points.txt,sha256=8wbw5csMIgBXhkwfgsgJeuFcoUc0WsucUxmOyml2aoA,209
68
- dcicutils-8.4.0.1b10.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,,