dcicutils 8.4.0.1b11__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.
@@ -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,,