dcicutils 8.5.0.1b6__py3-none-any.whl → 8.5.0.1b7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dcicutils/portal_utils.py +90 -64
- dcicutils/structured_data.py +3 -6
- {dcicutils-8.5.0.1b6.dist-info → dcicutils-8.5.0.1b7.dist-info}/METADATA +1 -1
- {dcicutils-8.5.0.1b6.dist-info → dcicutils-8.5.0.1b7.dist-info}/RECORD +7 -7
- {dcicutils-8.5.0.1b6.dist-info → dcicutils-8.5.0.1b7.dist-info}/LICENSE.txt +0 -0
- {dcicutils-8.5.0.1b6.dist-info → dcicutils-8.5.0.1b7.dist-info}/WHEEL +0 -0
- {dcicutils-8.5.0.1b6.dist-info → dcicutils-8.5.0.1b7.dist-info}/entry_points.txt +0 -0
dcicutils/portal_utils.py
CHANGED
@@ -1,13 +1,17 @@
|
|
1
1
|
from collections import deque
|
2
2
|
import io
|
3
3
|
import json
|
4
|
-
from pyramid.
|
5
|
-
from pyramid.
|
4
|
+
from pyramid.config import Configurator as PyramidConfigurator
|
5
|
+
from pyramid.paster import get_app as pyramid_get_app
|
6
|
+
from pyramid.response import Response as PyramidResponse
|
7
|
+
from pyramid.router import Router as PyramidRouter
|
6
8
|
import os
|
7
9
|
import re
|
8
10
|
import requests
|
9
11
|
from requests.models import Response as RequestResponse
|
10
|
-
from typing import Optional, Type, Union
|
12
|
+
from typing import Callable, Dict, List, Optional, Type, Union
|
13
|
+
from uuid import uuid4 as uuid
|
14
|
+
# from waitress import serve
|
11
15
|
from webtest.app import TestApp, TestResponse
|
12
16
|
from dcicutils.common import OrchestratedApp, ORCHESTRATED_APPS
|
13
17
|
from dcicutils.ff_utils import get_metadata, get_schema, patch_metadata, post_metadata
|
@@ -37,7 +41,7 @@ class Portal:
|
|
37
41
|
KEYS_FILE_DIRECTORY = os.path.expanduser(f"~")
|
38
42
|
|
39
43
|
def __init__(self,
|
40
|
-
arg: Optional[Union[Portal, TestApp, VirtualApp,
|
44
|
+
arg: Optional[Union[Portal, TestApp, VirtualApp, PyramidRouter, dict, tuple, str]] = None,
|
41
45
|
env: Optional[str] = None, server: Optional[str] = None,
|
42
46
|
app: Optional[OrchestratedApp] = None) -> None:
|
43
47
|
|
@@ -69,14 +73,14 @@ class Portal:
|
|
69
73
|
self._app = portal._app
|
70
74
|
self._vapp = portal._vapp
|
71
75
|
|
72
|
-
def init_from_vapp(vapp: Union[TestApp, VirtualApp,
|
76
|
+
def init_from_vapp(vapp: Union[TestApp, VirtualApp, PyramidRouter], unspecified: Optional[list] = []) -> None:
|
73
77
|
init(unspecified)
|
74
|
-
self._vapp = Portal.
|
78
|
+
self._vapp = Portal._create_vapp(vapp)
|
75
79
|
|
76
80
|
def init_from_ini_file(ini_file: str, unspecified: Optional[list] = []) -> None:
|
77
81
|
init(unspecified)
|
78
82
|
self._ini_file = ini_file
|
79
|
-
self._vapp = Portal.
|
83
|
+
self._vapp = Portal._create_vapp(ini_file)
|
80
84
|
|
81
85
|
def init_from_key(key: dict, server: Optional[str], unspecified: Optional[list] = []) -> None:
|
82
86
|
init(unspecified)
|
@@ -138,7 +142,7 @@ class Portal:
|
|
138
142
|
|
139
143
|
if isinstance(arg, Portal):
|
140
144
|
init_from_portal(arg, unspecified=[env, server, app])
|
141
|
-
elif isinstance(arg, (TestApp, VirtualApp,
|
145
|
+
elif isinstance(arg, (TestApp, VirtualApp, PyramidRouter)):
|
142
146
|
init_from_vapp(arg, unspecified=[env, server, app])
|
143
147
|
elif isinstance(arg, str) and arg.endswith(".ini"):
|
144
148
|
init_from_ini_file(arg, unspecified=[env, server, app])
|
@@ -201,35 +205,36 @@ class Portal:
|
|
201
205
|
def patch_metadata(self, object_id: str, data: str) -> Optional[dict]:
|
202
206
|
if self._key:
|
203
207
|
return patch_metadata(obj_id=object_id, patch_item=data, key=self._key)
|
204
|
-
return self.patch(f"/{object_id}", data)
|
208
|
+
return self.patch(f"/{object_id}", data).json()
|
205
209
|
|
206
210
|
def post_metadata(self, object_type: str, data: str) -> Optional[dict]:
|
207
211
|
if self._key:
|
208
212
|
return post_metadata(schema_name=object_type, post_item=data, key=self._key)
|
209
|
-
return self.post(f"/{object_type}", data)
|
213
|
+
return self.post(f"/{object_type}", data).json()
|
210
214
|
|
211
215
|
def get(self, uri: str, follow: bool = True, **kwargs) -> Optional[Union[RequestResponse, TestResponse]]:
|
212
|
-
if self._vapp:
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
return
|
216
|
+
if not self._vapp:
|
217
|
+
return requests.get(self.url(uri), allow_redirects=follow, **self._kwargs(**kwargs))
|
218
|
+
response = self._vapp.get(self.url(uri), **self._kwargs(**kwargs))
|
219
|
+
if response and response.status_code in [301, 302, 303, 307, 308] and follow:
|
220
|
+
response = response.follow()
|
221
|
+
return self._response(response)
|
218
222
|
|
219
223
|
def patch(self, uri: str, data: Optional[dict] = None,
|
220
224
|
json: Optional[dict] = None, **kwargs) -> Optional[Union[RequestResponse, TestResponse]]:
|
221
|
-
if self._vapp:
|
222
|
-
return
|
223
|
-
return
|
225
|
+
if not self._vapp:
|
226
|
+
return requests.patch(self.url(uri), data=data, json=json, **self._kwargs(**kwargs))
|
227
|
+
return self._response(self._vapp.patch_json(self.url(uri), json or data, **self._kwargs(**kwargs)))
|
224
228
|
|
225
229
|
def post(self, uri: str, data: Optional[dict] = None, json: Optional[dict] = None,
|
226
230
|
files: Optional[dict] = None, **kwargs) -> Optional[Union[RequestResponse, TestResponse]]:
|
227
|
-
if self._vapp:
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
231
|
+
if not self._vapp:
|
232
|
+
return requests.post(self.url(uri), data=data, json=json, files=files, **self._kwargs(**kwargs))
|
233
|
+
if files:
|
234
|
+
response = self._vapp.post(self.url(uri), json or data, upload_files=files, **self._kwargs(**kwargs))
|
235
|
+
else:
|
236
|
+
response = self._vapp.post_json(self.url(uri), json or data, upload_files=files, **self._kwargs(**kwargs))
|
237
|
+
return self._response(response)
|
233
238
|
|
234
239
|
def get_schema(self, schema_name: str) -> Optional[dict]:
|
235
240
|
return get_schema(self.schema_name(schema_name), portal_vapp=self._vapp, key=self._key)
|
@@ -311,7 +316,7 @@ class Portal:
|
|
311
316
|
if is_valid_app(app) or (app := infer_app_from_env(env)):
|
312
317
|
return os.path.join(Portal.KEYS_FILE_DIRECTORY, f".{app.lower()}-keys.json")
|
313
318
|
|
314
|
-
def _response(self, response) -> Optional[RequestResponse]:
|
319
|
+
def _response(self, response: TestResponse) -> Optional[RequestResponse]:
|
315
320
|
if response and isinstance(getattr(response.__class__, "json"), property):
|
316
321
|
class RequestResponseWrapper: # For consistency change json property to method.
|
317
322
|
def __init__(self, response, **kwargs):
|
@@ -325,51 +330,72 @@ class Portal:
|
|
325
330
|
return response
|
326
331
|
|
327
332
|
@staticmethod
|
328
|
-
def create_for_testing(
|
329
|
-
if isinstance(
|
330
|
-
return Portal(Portal.
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
"
|
355
|
-
|
356
|
-
|
357
|
-
])
|
358
|
-
with temporary_file(content=minimal_ini_for_testing_local, suffix=".ini") as minimal_ini_file:
|
359
|
-
return Portal(Portal._create_testapp(minimal_ini_file))
|
333
|
+
def create_for_testing(arg: Optional[Union[str, bool, List[dict], dict, Callable]] = None) -> Portal:
|
334
|
+
if isinstance(arg, list) or isinstance(arg, dict) or isinstance(arg, Callable):
|
335
|
+
return Portal(Portal._create_router_for_testing(arg))
|
336
|
+
if isinstance(arg, str) and arg.endswith(".ini"):
|
337
|
+
return Portal(Portal._create_vapp(arg))
|
338
|
+
if arg == "local" or arg is True:
|
339
|
+
minimal_ini_for_testing = "\n".join([
|
340
|
+
"[app:app]\nuse = egg:encoded\nfile_upload_bucket = dummy",
|
341
|
+
"sqlalchemy.url = postgresql://postgres@localhost:5441/postgres?host=/tmp/snovault/pgdata",
|
342
|
+
"multiauth.groupfinder = encoded.authorization.smaht_groupfinder",
|
343
|
+
"multiauth.policies = auth0 session remoteuser accesskey",
|
344
|
+
"multiauth.policy.session.namespace = mailto",
|
345
|
+
"multiauth.policy.session.use = encoded.authentication.NamespacedAuthenticationPolicy",
|
346
|
+
"multiauth.policy.session.base = pyramid.authentication.SessionAuthenticationPolicy",
|
347
|
+
"multiauth.policy.remoteuser.namespace = remoteuser",
|
348
|
+
"multiauth.policy.remoteuser.use = encoded.authentication.NamespacedAuthenticationPolicy",
|
349
|
+
"multiauth.policy.remoteuser.base = pyramid.authentication.RemoteUserAuthenticationPolicy",
|
350
|
+
"multiauth.policy.accesskey.namespace = accesskey",
|
351
|
+
"multiauth.policy.accesskey.use = encoded.authentication.NamespacedAuthenticationPolicy",
|
352
|
+
"multiauth.policy.accesskey.base = encoded.authentication.BasicAuthAuthenticationPolicy",
|
353
|
+
"multiauth.policy.accesskey.check = encoded.authentication.basic_auth_check",
|
354
|
+
"multiauth.policy.auth0.use = encoded.authentication.NamespacedAuthenticationPolicy",
|
355
|
+
"multiauth.policy.auth0.namespace = auth0",
|
356
|
+
"multiauth.policy.auth0.base = encoded.authentication.Auth0AuthenticationPolicy"
|
357
|
+
])
|
358
|
+
else:
|
359
|
+
minimal_ini_for_testing = "[app:app]\nuse = egg:encoded\nsqlalchemy.url = postgresql://dummy\n"
|
360
|
+
with temporary_file(content=minimal_ini_for_testing, suffix=".ini") as ini_file:
|
361
|
+
return Portal(Portal._create_vapp(ini_file))
|
360
362
|
|
361
363
|
@staticmethod
|
362
|
-
def
|
364
|
+
def _create_vapp(arg: Union[TestApp, VirtualApp, PyramidRouter, str] = None) -> TestApp:
|
363
365
|
if isinstance(arg, TestApp):
|
364
366
|
return arg
|
365
367
|
elif isinstance(arg, VirtualApp):
|
366
368
|
if not isinstance(arg.wrapped_app, TestApp):
|
367
|
-
raise Exception("Portal.
|
369
|
+
raise Exception("Portal._create_vapp VirtualApp argument error.")
|
368
370
|
return arg.wrapped_app
|
369
|
-
if isinstance(arg,
|
371
|
+
if isinstance(arg, PyramidRouter):
|
370
372
|
router = arg
|
371
|
-
elif isinstance(arg, str) or arg
|
372
|
-
router =
|
373
|
+
elif isinstance(arg, str) or not arg:
|
374
|
+
router = pyramid_get_app(arg or "development.ini", "app")
|
373
375
|
else:
|
374
|
-
raise Exception("Portal.
|
376
|
+
raise Exception("Portal._create_vapp argument error.")
|
375
377
|
return TestApp(router, {"HTTP_ACCEPT": "application/json", "REMOTE_USER": "TEST"})
|
378
|
+
|
379
|
+
@staticmethod
|
380
|
+
def _create_router_for_testing(endpoints: Optional[List[Dict[str, Union[str, Callable]]]] = None):
|
381
|
+
if isinstance(endpoints, dict):
|
382
|
+
endpoints = [endpoints]
|
383
|
+
elif isinstance(endpoints, Callable):
|
384
|
+
endpoints = [{"path": "/", "method": "GET", "function": endpoints}]
|
385
|
+
if not isinstance(endpoints, list) or not endpoints:
|
386
|
+
endpoints = [{"path": "/", "method": "GET", "function": lambda request: {"status": "OK"}}]
|
387
|
+
with PyramidConfigurator() as config:
|
388
|
+
nendpoints = 0
|
389
|
+
for endpoint in endpoints:
|
390
|
+
if (endpoint_path := endpoint.get("path")) and (endpoint_function := endpoint.get("function")):
|
391
|
+
endpoint_method = endpoint.get("method", "GET")
|
392
|
+
def endpoint_wrapper(request): # noqa
|
393
|
+
response = endpoint_function(request)
|
394
|
+
return PyramidResponse(json.dumps(response), content_type="application/json; charset=utf-8")
|
395
|
+
endpoint_id = str(uuid())
|
396
|
+
config.add_route(endpoint_id, endpoint_path)
|
397
|
+
config.add_view(endpoint_wrapper, route_name=endpoint_id, request_method=endpoint_method)
|
398
|
+
nendpoints += 1
|
399
|
+
if nendpoints == 0:
|
400
|
+
return Portal._create_router_for_testing([])
|
401
|
+
return config.make_wsgi_app()
|
dcicutils/structured_data.py
CHANGED
@@ -616,12 +616,9 @@ class Portal(PortalBase):
|
|
616
616
|
return self.get_metadata(f"/{type_name}/{value}") is not None
|
617
617
|
|
618
618
|
@staticmethod
|
619
|
-
def create_for_testing(
|
620
|
-
|
621
|
-
|
622
|
-
@staticmethod
|
623
|
-
def create_for_testing_local(ini_file: Optional[str] = None, schemas: Optional[List[dict]] = None) -> Portal:
|
624
|
-
return Portal(PortalBase.create_for_testing_local(ini_file), schemas=schemas)
|
619
|
+
def create_for_testing(arg: Optional[Union[str, bool, List[dict], dict, Callable]] = None,
|
620
|
+
schemas: Optional[List[dict]] = None) -> Portal:
|
621
|
+
return Portal(PortalBase.create_for_testing(arg), schemas=schemas)
|
625
622
|
|
626
623
|
|
627
624
|
def _split_dotted_string(value: str):
|
@@ -43,7 +43,7 @@ dcicutils/log_utils.py,sha256=7pWMc6vyrorUZQf-V-M3YC6zrPgNhuV_fzm9xqTPph0,10883
|
|
43
43
|
dcicutils/misc_utils.py,sha256=nRjLEORY35YmJwTjO0fnauBPznaI_bkVasIW8PccDYM,100179
|
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=
|
46
|
+
dcicutils/portal_utils.py,sha256=IZfwtbkirNiSSvpUzkQxHBedzaSgMiiVbkLLKzHEvVI,20043
|
47
47
|
dcicutils/project_utils.py,sha256=qPdCaFmWUVBJw4rw342iUytwdQC0P-XKpK4mhyIulMM,31250
|
48
48
|
dcicutils/qa_checkers.py,sha256=cdXjeL0jCDFDLT8VR8Px78aS10hwNISOO5G_Zv2TZ6M,20534
|
49
49
|
dcicutils/qa_utils.py,sha256=TT0SiJWiuxYvbsIyhK9VO4uV_suxhB6CpuC4qPacCzQ,160208
|
@@ -56,14 +56,14 @@ dcicutils/secrets_utils.py,sha256=8dppXAsiHhJzI6NmOcvJV5ldvKkQZzh3Fl-cb8Wm7MI,19
|
|
56
56
|
dcicutils/sheet_utils.py,sha256=VlmzteONW5VF_Q4vo0yA5vesz1ViUah1MZ_yA1rwZ0M,33629
|
57
57
|
dcicutils/snapshot_utils.py,sha256=ymP7PXH6-yEiXAt75w0ldQFciGNqWBClNxC5gfX2FnY,22961
|
58
58
|
dcicutils/ssl_certificate_utils.py,sha256=F0ifz_wnRRN9dfrfsz7aCp4UDLgHEY8LaK7PjnNvrAQ,9707
|
59
|
-
dcicutils/structured_data.py,sha256=
|
59
|
+
dcicutils/structured_data.py,sha256=ziugsIE_FlYRFQIl2GJqwduRa4yIBPbHBQRYPSeUzSk,32713
|
60
60
|
dcicutils/task_utils.py,sha256=MF8ujmTD6-O2AC2gRGPHyGdUrVKgtr8epT5XU8WtNjk,8082
|
61
61
|
dcicutils/trace_utils.py,sha256=g8kwV4ebEy5kXW6oOrEAUsurBcCROvwtZqz9fczsGRE,1769
|
62
62
|
dcicutils/validation_utils.py,sha256=cMZIU2cY98FYtzK52z5WUYck7urH6JcqOuz9jkXpqzg,14797
|
63
63
|
dcicutils/variant_utils.py,sha256=2H9azNx3xAj-MySg-uZ2SFqbWs4kZvf61JnK6b-h4Qw,4343
|
64
64
|
dcicutils/zip_utils.py,sha256=0OXR0aLNwyLIZOzIFTM_5DOun7dxIv6TIZbFiithkO0,3276
|
65
|
-
dcicutils-8.5.0.
|
66
|
-
dcicutils-8.5.0.
|
67
|
-
dcicutils-8.5.0.
|
68
|
-
dcicutils-8.5.0.
|
69
|
-
dcicutils-8.5.0.
|
65
|
+
dcicutils-8.5.0.1b7.dist-info/LICENSE.txt,sha256=t0_-jIjqxNnymZoNJe-OltRIuuF8qfhN0ATlHyrUJPk,1102
|
66
|
+
dcicutils-8.5.0.1b7.dist-info/METADATA,sha256=AZPMmFxRxXIpn3-mhRMhuS3mHK9YFWjpsoA3T2TXo-g,3314
|
67
|
+
dcicutils-8.5.0.1b7.dist-info/WHEEL,sha256=7Z8_27uaHI_UZAc4Uox4PpBhQ9Y5_modZXWMxtUi4NU,88
|
68
|
+
dcicutils-8.5.0.1b7.dist-info/entry_points.txt,sha256=8wbw5csMIgBXhkwfgsgJeuFcoUc0WsucUxmOyml2aoA,209
|
69
|
+
dcicutils-8.5.0.1b7.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|