dcicutils 8.5.0.1b4__tar.gz → 8.5.0.1b6__tar.gz
Sign up to get free protection for your applications and to get access to all the features.
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/PKG-INFO +1 -1
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/portal_utils.py +187 -105
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/structured_data.py +10 -14
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/pyproject.toml +1 -1
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/LICENSE.txt +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/README.rst +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/__init__.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/base.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/beanstalk_utils.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/bundle_utils.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/cloudformation_utils.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/codebuild_utils.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/command_utils.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/common.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/contribution_scripts.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/contribution_utils.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/creds_utils.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/data_readers.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/data_utils.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/deployment_utils.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/diff_utils.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/docker_utils.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/ecr_scripts.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/ecr_utils.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/ecs_utils.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/env_base.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/env_manager.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/env_scripts.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/env_utils.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/env_utils_legacy.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/es_utils.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/exceptions.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/ff_mocks.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/ff_utils.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/function_cache_decorator.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/glacier_utils.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/jh_utils.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/kibana/dashboards.json +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/kibana/readme.md +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/lang_utils.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/license_policies/c4-infrastructure.jsonc +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/license_policies/c4-python-infrastructure.jsonc +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/license_policies/park-lab-common-server.jsonc +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/license_policies/park-lab-common.jsonc +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/license_policies/park-lab-gpl-pipeline.jsonc +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/license_policies/park-lab-pipeline.jsonc +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/license_utils.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/log_utils.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/misc_utils.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/obfuscation_utils.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/opensearch_utils.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/project_utils.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/qa_checkers.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/qa_utils.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/redis_tools.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/redis_utils.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/s3_utils.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/scripts/publish_to_pypi.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/scripts/run_license_checker.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/secrets_utils.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/sheet_utils.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/snapshot_utils.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/ssl_certificate_utils.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/task_utils.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/trace_utils.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/validation_utils.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/variant_utils.py +0 -0
- {dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/zip_utils.py +0 -0
@@ -1,19 +1,20 @@
|
|
1
1
|
from collections import deque
|
2
|
+
import io
|
3
|
+
import json
|
2
4
|
from pyramid.paster import get_app
|
3
5
|
from pyramid.router import Router
|
6
|
+
import os
|
4
7
|
import re
|
5
8
|
import requests
|
6
9
|
from requests.models import Response as RequestResponse
|
7
10
|
from typing import Optional, Type, Union
|
8
11
|
from webtest.app import TestApp, TestResponse
|
9
|
-
from dcicutils.common import OrchestratedApp,
|
10
|
-
from dcicutils.creds_utils import CGAPKeyManager, FourfrontKeyManager, SMaHTKeyManager
|
12
|
+
from dcicutils.common import OrchestratedApp, ORCHESTRATED_APPS
|
11
13
|
from dcicutils.ff_utils import get_metadata, get_schema, patch_metadata, post_metadata
|
12
14
|
from dcicutils.misc_utils import to_camel_case, VirtualApp
|
13
15
|
from dcicutils.zip_utils import temporary_file
|
14
16
|
|
15
17
|
Portal = Type["Portal"] # Forward type reference for type hints.
|
16
|
-
FILE_SCHEMA_NAME = "File"
|
17
18
|
|
18
19
|
|
19
20
|
class Portal:
|
@@ -32,105 +33,166 @@ class Portal:
|
|
32
33
|
6. From a given "vapp" value (which is assumed to be a TestApp or VirtualApp).
|
33
34
|
7. From another Portal object; or from a a pyramid Router object.
|
34
35
|
"""
|
36
|
+
FILE_SCHEMA_NAME = "File"
|
37
|
+
KEYS_FILE_DIRECTORY = os.path.expanduser(f"~")
|
38
|
+
|
35
39
|
def __init__(self,
|
36
|
-
arg: Optional[Union[
|
37
|
-
env: Optional[str] = None,
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
self._vapp = portal._vapp
|
59
|
-
self._env = portal._env
|
60
|
-
self._app = portal._app
|
61
|
-
self._server = portal._server
|
40
|
+
arg: Optional[Union[Portal, TestApp, VirtualApp, Router, dict, tuple, str]] = None,
|
41
|
+
env: Optional[str] = None, server: Optional[str] = None,
|
42
|
+
app: Optional[OrchestratedApp] = None) -> None:
|
43
|
+
|
44
|
+
def init(unspecified: Optional[list] = []) -> None:
|
45
|
+
self._ini_file = None
|
46
|
+
self._key = None
|
47
|
+
self._key_pair = None
|
48
|
+
self._key_id = None
|
49
|
+
self._secret = None
|
50
|
+
self._keys_file = None
|
51
|
+
self._env = None
|
52
|
+
self._server = None
|
53
|
+
self._app = None
|
54
|
+
self._vapp = None
|
55
|
+
for arg in unspecified:
|
56
|
+
if arg is not None:
|
57
|
+
raise Exception("Portal init error; extraneous args.")
|
58
|
+
|
59
|
+
def init_from_portal(portal: Portal, unspecified: Optional[list] = None) -> None:
|
60
|
+
init(unspecified)
|
61
|
+
self._ini_file = portal._ini_file
|
62
62
|
self._key = portal._key
|
63
63
|
self._key_pair = portal._key_pair
|
64
64
|
self._key_id = portal._key_id
|
65
|
-
self.
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
self._key = None
|
72
|
-
self._key_pair = None
|
73
|
-
self._key_id = None
|
74
|
-
self._key_file = None
|
75
|
-
if isinstance(portal, (VirtualApp, TestApp)):
|
76
|
-
self._vapp = portal
|
77
|
-
elif isinstance(portal, (Router, str)):
|
78
|
-
self._vapp = Portal._create_vapp(portal)
|
79
|
-
elif isinstance(key, dict):
|
80
|
-
self._key = key
|
81
|
-
self._key_pair = (key.get("key"), key.get("secret")) if key else None
|
82
|
-
if key_server := key.get("server"):
|
83
|
-
self._server = key_server
|
84
|
-
elif isinstance(key, tuple) and len(key) >= 2:
|
85
|
-
self._key = {"key": key[0], "secret": key[1]}
|
86
|
-
self._key_pair = key
|
87
|
-
elif isinstance(env, str):
|
88
|
-
key_managers = {APP_CGAP: CGAPKeyManager, APP_FOURFRONT: FourfrontKeyManager, APP_SMAHT: SMaHTKeyManager}
|
89
|
-
if not (key_manager := key_managers.get(self._app)) or not (key_manager := key_manager()):
|
90
|
-
raise Exception(f"Invalid app name: {self._app} (valid: {', '.join(ORCHESTRATED_APPS)}).")
|
91
|
-
if isinstance(env, str):
|
92
|
-
self._key = key_manager.get_keydict_for_env(env)
|
93
|
-
if key_server := self._key.get("server"):
|
94
|
-
self._server = key_server
|
95
|
-
elif isinstance(self._server, str):
|
96
|
-
self._key = key_manager.get_keydict_for_server(self._server)
|
97
|
-
self._key_pair = key_manager.keydict_to_keypair(self._key) if self._key else None
|
98
|
-
self._key_file = key_manager.keys_file
|
99
|
-
if self._key and (key_id := self._key.get("key")):
|
100
|
-
self._key_id = key_id
|
101
|
-
elif self._key_pair and (key_id := self._key_pair[1]):
|
102
|
-
self._key_id = key_id
|
65
|
+
self._secret = portal._secret
|
66
|
+
self._keys_file = portal._keys_file
|
67
|
+
self._env = portal._env
|
68
|
+
self._server = portal._server
|
69
|
+
self._app = portal._app
|
70
|
+
self._vapp = portal._vapp
|
103
71
|
|
104
|
-
|
105
|
-
|
106
|
-
|
72
|
+
def init_from_vapp(vapp: Union[TestApp, VirtualApp, Router], unspecified: Optional[list] = []) -> None:
|
73
|
+
init(unspecified)
|
74
|
+
self._vapp = Portal._create_testapp(vapp)
|
107
75
|
|
108
|
-
|
109
|
-
|
110
|
-
|
76
|
+
def init_from_ini_file(ini_file: str, unspecified: Optional[list] = []) -> None:
|
77
|
+
init(unspecified)
|
78
|
+
self._ini_file = ini_file
|
79
|
+
self._vapp = Portal._create_testapp(ini_file)
|
80
|
+
|
81
|
+
def init_from_key(key: dict, server: Optional[str], unspecified: Optional[list] = []) -> None:
|
82
|
+
init(unspecified)
|
83
|
+
if (isinstance(key_id := key.get("key"), str) and key_id and
|
84
|
+
isinstance(secret := key.get("secret"), str) and secret): # noqa
|
85
|
+
self._key = {"key": key_id, "secret": secret}
|
86
|
+
self._key_id = key_id
|
87
|
+
self._secret = secret
|
88
|
+
self._key_pair = (key_id, secret)
|
89
|
+
if ((isinstance(server, str) and server) or (isinstance(server := key.get("server"), str) and server)):
|
90
|
+
if server := normalize_server(server):
|
91
|
+
self._key["server"] = self._server = server
|
92
|
+
if not self._key:
|
93
|
+
raise Exception("Portal init error; from key.")
|
94
|
+
|
95
|
+
def init_from_key_pair(key_pair: tuple, server: Optional[str], unspecified: Optional[list] = []) -> None:
|
96
|
+
if len(key_pair) == 2:
|
97
|
+
init_from_key({"key": key_pair[0], "secret": key_pair[1]}, server, unspecified)
|
98
|
+
else:
|
99
|
+
raise Exception("Portal init error; from key-pair.")
|
100
|
+
|
101
|
+
def init_from_keys_file(keys_file: str, env: Optional[str], server: Optional[str],
|
102
|
+
unspecified: Optional[list] = []) -> None:
|
103
|
+
try:
|
104
|
+
with io.open(keys_file) as f:
|
105
|
+
keys = json.load(f)
|
106
|
+
except Exception:
|
107
|
+
raise Exception(f"Portal init error; cannot open keys-file: {keys_file}")
|
108
|
+
if isinstance(env, str) and env and isinstance(key := keys.get(env), dict):
|
109
|
+
init_from_key(key, server)
|
110
|
+
self._keys_file = keys_file
|
111
|
+
self._env = env
|
112
|
+
elif isinstance(server, str) and server and (key := [k for k in keys if keys[k].get("server") == server]):
|
113
|
+
init_from_key(key, server)
|
114
|
+
self._keys_file = keys_file
|
115
|
+
elif len(keys) == 1 and (env := next(iter(keys))) and isinstance(key := keys[env], dict) and key:
|
116
|
+
init_from_key(key, server)
|
117
|
+
self._keys_file = keys_file
|
118
|
+
self._env = env
|
119
|
+
else:
|
120
|
+
raise Exception(f"Portal init error; {env or server or None} not found in keys-file: {keys_file}")
|
121
|
+
|
122
|
+
def init_from_env_server_app(env: str, server: str, app: Optional[str],
|
123
|
+
unspecified: Optional[list] = None) -> None:
|
124
|
+
return init_from_keys_file(self._default_keys_file(app, env), env, server, unspecified)
|
125
|
+
|
126
|
+
def normalize_server(server: str) -> Optional[str]:
|
127
|
+
prefix = ""
|
128
|
+
if (lserver := server.lower()).startswith("http://"):
|
129
|
+
prefix = "http://"
|
130
|
+
elif lserver.startswith("https://"):
|
131
|
+
prefix = "https://"
|
132
|
+
if prefix:
|
133
|
+
if (server := re.sub(r"/+", "/", server[len(prefix):])).startswith("/"):
|
134
|
+
server = server[1:]
|
135
|
+
if len(server) > 1 and server.endswith("/"):
|
136
|
+
server = server[:-1]
|
137
|
+
return prefix + server if server else None
|
138
|
+
|
139
|
+
if isinstance(arg, Portal):
|
140
|
+
init_from_portal(arg, unspecified=[env, server, app])
|
141
|
+
elif isinstance(arg, (TestApp, VirtualApp, Router)):
|
142
|
+
init_from_vapp(arg, unspecified=[env, server, app])
|
143
|
+
elif isinstance(arg, str) and arg.endswith(".ini"):
|
144
|
+
init_from_ini_file(arg, unspecified=[env, server, app])
|
145
|
+
elif isinstance(arg, dict):
|
146
|
+
init_from_key(arg, server, unspecified=[env, app])
|
147
|
+
elif isinstance(arg, tuple):
|
148
|
+
init_from_key_pair(arg, server, unspecified=[env, app])
|
149
|
+
elif isinstance(arg, str) and arg.endswith(".json"):
|
150
|
+
init_from_keys_file(arg, env, server, unspecified=[app])
|
151
|
+
elif isinstance(arg, str) and arg:
|
152
|
+
init_from_env_server_app(arg, server, app, unspecified=[env])
|
153
|
+
elif isinstance(env, str) and env:
|
154
|
+
init_from_env_server_app(env, server, app, unspecified=[arg])
|
155
|
+
else:
|
156
|
+
raise Exception("Portal init error; invalid args.")
|
111
157
|
|
112
158
|
@property
|
113
|
-
def
|
114
|
-
return self.
|
159
|
+
def ini_file(self) -> Optional[str]:
|
160
|
+
return self._ini_file
|
115
161
|
|
116
162
|
@property
|
117
|
-
def key(self):
|
163
|
+
def key(self) -> Optional[dict]:
|
118
164
|
return self._key
|
119
165
|
|
120
166
|
@property
|
121
|
-
def key_pair(self):
|
167
|
+
def key_pair(self) -> Optional[tuple]:
|
122
168
|
return self._key_pair
|
123
169
|
|
124
170
|
@property
|
125
|
-
def key_id(self):
|
171
|
+
def key_id(self) -> Optional[str]:
|
126
172
|
return self._key_id
|
127
173
|
|
128
174
|
@property
|
129
|
-
def
|
130
|
-
return self.
|
175
|
+
def secret(self) -> Optional[str]:
|
176
|
+
return self._secret
|
177
|
+
|
178
|
+
@property
|
179
|
+
def keys_file(self) -> Optional[str]:
|
180
|
+
return self._keys_file
|
181
|
+
|
182
|
+
@property
|
183
|
+
def env(self) -> Optional[str]:
|
184
|
+
return self._env
|
185
|
+
|
186
|
+
@property
|
187
|
+
def server(self) -> Optional[str]:
|
188
|
+
return self._server
|
131
189
|
|
132
190
|
@property
|
133
|
-
def
|
191
|
+
def app(self) -> Optional[str]:
|
192
|
+
return self._app
|
193
|
+
|
194
|
+
@property
|
195
|
+
def vapp(self) -> Optional[TestApp]:
|
134
196
|
return self._vapp
|
135
197
|
|
136
198
|
def get_metadata(self, object_id: str) -> Optional[dict]:
|
@@ -147,27 +209,27 @@ class Portal:
|
|
147
209
|
return self.post(f"/{object_type}", data)
|
148
210
|
|
149
211
|
def get(self, uri: str, follow: bool = True, **kwargs) -> Optional[Union[RequestResponse, TestResponse]]:
|
150
|
-
if
|
151
|
-
response = self._vapp.get(self.
|
212
|
+
if self._vapp:
|
213
|
+
response = self._vapp.get(self.url(uri), **self._kwargs(**kwargs))
|
152
214
|
if response and response.status_code in [301, 302, 303, 307, 308] and follow:
|
153
215
|
response = response.follow()
|
154
216
|
return self._response(response)
|
155
|
-
return requests.get(self.
|
217
|
+
return requests.get(self.url(uri), allow_redirects=follow, **self._kwargs(**kwargs))
|
156
218
|
|
157
219
|
def patch(self, uri: str, data: Optional[dict] = None,
|
158
220
|
json: Optional[dict] = None, **kwargs) -> Optional[Union[RequestResponse, TestResponse]]:
|
159
|
-
if
|
160
|
-
return self._vapp.patch_json(self.
|
161
|
-
return requests.patch(self.
|
221
|
+
if self._vapp:
|
222
|
+
return self._vapp.patch_json(self.url(uri), json or data, **self._kwargs(**kwargs))
|
223
|
+
return requests.patch(self.url(uri), data=data, json=json, **self._kwargs(**kwargs))
|
162
224
|
|
163
225
|
def post(self, uri: str, data: Optional[dict] = None, json: Optional[dict] = None,
|
164
226
|
files: Optional[dict] = None, **kwargs) -> Optional[Union[RequestResponse, TestResponse]]:
|
165
|
-
if
|
227
|
+
if self._vapp:
|
166
228
|
if files:
|
167
|
-
return self._vapp.post(self.
|
229
|
+
return self._vapp.post(self.url(uri), json or data, upload_files=files, **self._kwargs(**kwargs))
|
168
230
|
else:
|
169
|
-
return self._vapp.post_json(self.
|
170
|
-
return requests.post(self.
|
231
|
+
return self._vapp.post_json(self.url(uri), json or data, upload_files=files, **self._kwargs(**kwargs))
|
232
|
+
return requests.post(self.url(uri), data=data, json=json, files=files, **self._kwargs(**kwargs))
|
171
233
|
|
172
234
|
def get_schema(self, schema_name: str) -> Optional[dict]:
|
173
235
|
return get_schema(self.schema_name(schema_name), portal_vapp=self._vapp, key=self._key)
|
@@ -181,7 +243,7 @@ class Portal:
|
|
181
243
|
|
182
244
|
def is_file_schema(self, schema_name: str) -> bool:
|
183
245
|
if super_type_map := self.get_schemas_super_type_map():
|
184
|
-
if file_super_type := super_type_map.get(FILE_SCHEMA_NAME):
|
246
|
+
if file_super_type := super_type_map.get(Portal.FILE_SCHEMA_NAME):
|
185
247
|
return self.schema_name(schema_name) in file_super_type
|
186
248
|
return False
|
187
249
|
|
@@ -221,13 +283,14 @@ class Portal:
|
|
221
283
|
except Exception:
|
222
284
|
return False
|
223
285
|
|
224
|
-
def
|
286
|
+
def url(self, uri: str) -> str:
|
225
287
|
if not isinstance(uri, str) or not uri:
|
226
288
|
return "/"
|
227
|
-
if uri.lower().startswith("http://") or
|
289
|
+
if (luri := uri.lower()).startswith("http://") or luri.startswith("https://"):
|
228
290
|
return uri
|
229
|
-
uri
|
230
|
-
|
291
|
+
if not (uri := re.sub(r"/+", "/", uri)).startswith("/"):
|
292
|
+
uri = "/"
|
293
|
+
return self._server + uri if self._server else uri
|
231
294
|
|
232
295
|
def _kwargs(self, **kwargs) -> dict:
|
233
296
|
result_kwargs = {"headers":
|
@@ -238,6 +301,16 @@ class Portal:
|
|
238
301
|
result_kwargs["timeout"] = timeout
|
239
302
|
return result_kwargs
|
240
303
|
|
304
|
+
def _default_keys_file(self, app: Optional[str], env: Optional[str] = None) -> Optional[str]:
|
305
|
+
def is_valid_app(app: Optional[str]) -> bool: # noqa
|
306
|
+
return app and app.lower() in [name.lower() for name in ORCHESTRATED_APPS]
|
307
|
+
def infer_app_from_env(env: str) -> Optional[str]: # noqa
|
308
|
+
if isinstance(env, str) and (lenv := env.lower()):
|
309
|
+
if app := [app for app in ORCHESTRATED_APPS if lenv.startswith(app.lower())]:
|
310
|
+
return app[0]
|
311
|
+
if is_valid_app(app) or (app := infer_app_from_env(env)):
|
312
|
+
return os.path.join(Portal.KEYS_FILE_DIRECTORY, f".{app.lower()}-keys.json")
|
313
|
+
|
241
314
|
def _response(self, response) -> Optional[RequestResponse]:
|
242
315
|
if response and isinstance(getattr(response.__class__, "json"), property):
|
243
316
|
class RequestResponseWrapper: # For consistency change json property to method.
|
@@ -254,15 +327,15 @@ class Portal:
|
|
254
327
|
@staticmethod
|
255
328
|
def create_for_testing(ini_file: Optional[str] = None) -> Portal:
|
256
329
|
if isinstance(ini_file, str):
|
257
|
-
return Portal(Portal.
|
330
|
+
return Portal(Portal._create_testapp(ini_file))
|
258
331
|
minimal_ini_for_unit_testing = "[app:app]\nuse = egg:encoded\nsqlalchemy.url = postgresql://dummy\n"
|
259
332
|
with temporary_file(content=minimal_ini_for_unit_testing, suffix=".ini") as ini_file:
|
260
|
-
return Portal(Portal.
|
333
|
+
return Portal(Portal._create_testapp(ini_file))
|
261
334
|
|
262
335
|
@staticmethod
|
263
336
|
def create_for_testing_local(ini_file: Optional[str] = None) -> Portal:
|
264
337
|
if isinstance(ini_file, str) and ini_file:
|
265
|
-
return Portal(Portal.
|
338
|
+
return Portal(Portal._create_testapp(ini_file))
|
266
339
|
minimal_ini_for_testing_local = "\n".join([
|
267
340
|
"[app:app]\nuse = egg:encoded\nfile_upload_bucket = dummy",
|
268
341
|
"sqlalchemy.url = postgresql://postgres@localhost:5441/postgres?host=/tmp/snovault/pgdata",
|
@@ -283,11 +356,20 @@ class Portal:
|
|
283
356
|
"multiauth.policy.auth0.base = encoded.authentication.Auth0AuthenticationPolicy"
|
284
357
|
])
|
285
358
|
with temporary_file(content=minimal_ini_for_testing_local, suffix=".ini") as minimal_ini_file:
|
286
|
-
return Portal(Portal.
|
359
|
+
return Portal(Portal._create_testapp(minimal_ini_file))
|
287
360
|
|
288
361
|
@staticmethod
|
289
|
-
def
|
290
|
-
if isinstance(
|
291
|
-
return
|
292
|
-
|
293
|
-
|
362
|
+
def _create_testapp(arg: Union[TestApp, VirtualApp, Router, str] = None, app_name: Optional[str] = None) -> TestApp:
|
363
|
+
if isinstance(arg, TestApp):
|
364
|
+
return arg
|
365
|
+
elif isinstance(arg, VirtualApp):
|
366
|
+
if not isinstance(arg.wrapped_app, TestApp):
|
367
|
+
raise Exception("Portal._create_testapp VirtualApp argument error.")
|
368
|
+
return arg.wrapped_app
|
369
|
+
if isinstance(arg, Router):
|
370
|
+
router = arg
|
371
|
+
elif isinstance(arg, str) or arg is None:
|
372
|
+
router = get_app(arg or "development.ini", app_name or "app")
|
373
|
+
else:
|
374
|
+
raise Exception("Portal._create_testapp argument error.")
|
375
|
+
return TestApp(router, {"HTTP_ACCEPT": "application/json", "REMOTE_USER": "TEST"})
|
@@ -43,8 +43,8 @@ class StructuredDataSet:
|
|
43
43
|
|
44
44
|
def __init__(self, file: Optional[str] = None, portal: Optional[Union[VirtualApp, TestApp, Portal]] = None,
|
45
45
|
schemas: Optional[List[dict]] = None, autoadd: Optional[dict] = None,
|
46
|
-
|
47
|
-
self.data = {}
|
46
|
+
order: Optional[List[str]] = None, prune: bool = True) -> None:
|
47
|
+
self.data = {}
|
48
48
|
self._portal = Portal(portal, data=self.data, schemas=schemas) if portal else None
|
49
49
|
self._order = order
|
50
50
|
self._prune = prune
|
@@ -113,7 +113,7 @@ class StructuredDataSet:
|
|
113
113
|
def _load_file(self, file: str) -> None:
|
114
114
|
# Returns a dictionary where each property is the name (i.e. the type) of the data,
|
115
115
|
# and the value is array of dictionaries for the data itself. Handle these kinds of files:
|
116
|
-
# 1. Single CSV
|
116
|
+
# 1. Single CSV, TSV, or JSON file, where the (base) name of the file is the data type name.
|
117
117
|
# 2. Single Excel file containing one or more sheets, where each sheet
|
118
118
|
# represents (i.e. is named for, and contains data for) a different type.
|
119
119
|
# 3. Zip file (.zip or .tar.gz or .tgz or .tar), containing data files to load, where the
|
@@ -483,7 +483,6 @@ class Schema:
|
|
483
483
|
if unique:
|
484
484
|
typeinfo[key]["unique"] = True
|
485
485
|
result.update(typeinfo)
|
486
|
-
# result.update(self._create_typeinfo(array_property_items, parent_key=key))
|
487
486
|
continue
|
488
487
|
result[key] = {"type": property_value_type, "map": self._map_function({**property_value, "column": key})}
|
489
488
|
if ARRAY_NAME_SUFFIX_CHAR in key:
|
@@ -551,16 +550,13 @@ class Portal(PortalBase):
|
|
551
550
|
|
552
551
|
def __init__(self,
|
553
552
|
arg: Optional[Union[VirtualApp, TestApp, Router, Portal, dict, tuple, str]] = None,
|
554
|
-
env: Optional[str] = None,
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
if isinstance(portal, Portal):
|
562
|
-
self._schemas = schemas if schemas is not None else portal._schemas # Explicitly specified/known schemas.
|
563
|
-
self._data = data if data is not None else portal._data # Data set being loaded; e.g. by StructuredDataSet.
|
553
|
+
env: Optional[str] = None, server: Optional[str] = None,
|
554
|
+
app: Optional[OrchestratedApp] = None,
|
555
|
+
data: Optional[dict] = None, schemas: Optional[List[dict]] = None) -> None:
|
556
|
+
super().__init__(arg, env=env, server=server, app=app)
|
557
|
+
if isinstance(arg, Portal):
|
558
|
+
self._schemas = schemas if schemas is not None else arg._schemas # Explicitly specified/known schemas.
|
559
|
+
self._data = data if data is not None else arg._data # Data set being loaded; e.g. by StructuredDataSet.
|
564
560
|
else:
|
565
561
|
self._schemas = schemas
|
566
562
|
self._data = data
|
@@ -1,6 +1,6 @@
|
|
1
1
|
[tool.poetry]
|
2
2
|
name = "dcicutils"
|
3
|
-
version = "8.5.0.
|
3
|
+
version = "8.5.0.1b6" # TODO: To become 8.6.0
|
4
4
|
description = "Utility package for interacting with the 4DN Data Portal and other 4DN resources"
|
5
5
|
authors = ["4DN-DCIC Team <support@4dnucleome.org>"]
|
6
6
|
license = "MIT"
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/license_policies/c4-infrastructure.jsonc
RENAMED
File without changes
|
File without changes
|
{dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/license_policies/park-lab-common-server.jsonc
RENAMED
File without changes
|
{dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/license_policies/park-lab-common.jsonc
RENAMED
File without changes
|
{dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/license_policies/park-lab-gpl-pipeline.jsonc
RENAMED
File without changes
|
{dcicutils-8.5.0.1b4 → dcicutils-8.5.0.1b6}/dcicutils/license_policies/park-lab-pipeline.jsonc
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|