dcicutils 8.5.0.1b4__py3-none-any.whl → 8.5.0.1b6__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 CHANGED
@@ -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, APP_CGAP, APP_FOURFRONT, APP_SMAHT, ORCHESTRATED_APPS
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[VirtualApp, TestApp, Router, Portal, dict, tuple, str]] = None,
37
- env: Optional[str] = None, app: Optional[OrchestratedApp] = None, server: Optional[str] = None,
38
- key: Optional[Union[dict, tuple]] = None,
39
- vapp: Optional[Union[VirtualApp, TestApp, Router, Portal, str]] = None,
40
- portal: Optional[Union[VirtualApp, TestApp, Router, Portal, str]] = None) -> Portal:
41
- if vapp and not portal:
42
- portal = vapp
43
- if ((isinstance(arg, (VirtualApp, TestApp, Router, Portal)) or
44
- isinstance(arg, str) and arg.endswith(".ini")) and not portal):
45
- portal = arg
46
- elif isinstance(arg, str) and not env:
47
- env = arg
48
- elif (isinstance(arg, dict) or isinstance(arg, tuple)) and not key:
49
- key = arg
50
- if not app and env:
51
- if env.startswith(APP_SMAHT):
52
- app = APP_SMAHT
53
- elif env.startswith(APP_CGAP):
54
- app = APP_CGAP
55
- elif env.startswith(APP_FOURFRONT):
56
- app = APP_FOURFRONT
57
- if isinstance(portal, Portal):
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._key_file = portal._key_file
66
- return
67
- self._vapp = None
68
- self._env = env
69
- self._app = app
70
- self._server = server
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
- @property
105
- def env(self):
106
- return self._env
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
- @property
109
- def app(self):
110
- return self._app
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 server(self):
114
- return self._server
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 key_file(self):
130
- return self._key_file
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 vapp(self):
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 isinstance(self._vapp, (VirtualApp, TestApp)):
151
- response = self._vapp.get(self._uri(uri), **self._kwargs(**kwargs))
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._uri(uri), allow_redirects=follow, **self._kwargs(**kwargs))
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 isinstance(self._vapp, (VirtualApp, TestApp)):
160
- return self._vapp.patch_json(self._uri(uri), json or data, **self._kwargs(**kwargs))
161
- return requests.patch(self._uri(uri), json=json or data, **self._kwargs(**kwargs))
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 isinstance(self._vapp, (VirtualApp, TestApp)):
227
+ if self._vapp:
166
228
  if files:
167
- return self._vapp.post(self._uri(uri), json or data, upload_files=files, **self._kwargs(**kwargs))
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._uri(uri), json or data, upload_files=files, **self._kwargs(**kwargs))
170
- return requests.post(self._uri(uri), json=json or data, files=files, **self._kwargs(**kwargs))
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 _uri(self, uri: str) -> str:
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 uri.lower().startswith("https://"):
289
+ if (luri := uri.lower()).startswith("http://") or luri.startswith("https://"):
228
290
  return uri
229
- uri = re.sub(r"/+", "/", uri)
230
- return (self._server + ("/" if not uri.startswith("/") else "") + uri) if self._server else uri
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._create_vapp(ini_file))
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._create_vapp(ini_file))
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._create_vapp(ini_file))
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._create_vapp(minimal_ini_file))
359
+ return Portal(Portal._create_testapp(minimal_ini_file))
287
360
 
288
361
  @staticmethod
289
- def _create_vapp(value: Union[str, Router, TestApp] = "development.ini", app_name: str = "app") -> TestApp:
290
- if isinstance(value, TestApp):
291
- return value
292
- app = value if isinstance(value, Router) else get_app(value, app_name)
293
- return TestApp(app, {"HTTP_ACCEPT": "application/json", "REMOTE_USER": "TEST"})
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
- data: Optional[List[dict]] = None, order: Optional[List[str]] = None, prune: bool = True) -> None:
47
- self.data = {} if not data else data # If portal is None then no schemas nor refs.
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 of JSON file, where the (base) name of the file is the data type name.
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, app: OrchestratedApp = None, server: Optional[str] = None,
555
- key: Optional[Union[dict, tuple]] = None,
556
- portal: Optional[Union[VirtualApp, TestApp, Router, Portal, str]] = None,
557
- data: Optional[dict] = None, schemas: Optional[List[dict]] = None) -> Optional[Portal]:
558
- super().__init__(arg, env=env, app=app, server=server, key=key, portal=portal)
559
- if isinstance(arg, Portal) and not portal:
560
- portal = arg
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
  Metadata-Version: 2.1
2
2
  Name: dcicutils
3
- Version: 8.5.0.1b4
3
+ Version: 8.5.0.1b6
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,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=Wh918ZKpUJFbt7w6Bn5G7v-0k6ImOUWMFmE9Oxt1ZN4,14560
46
+ dcicutils/portal_utils.py,sha256=PLIKONo_BhVrf-r5fkXAaxP5IQZRjvPjf83YxvRx0ZE,18393
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=tMKBhq6OuM2t6iDxIPBFcxV66MiwmOHTBeACxhvkbiQ,33307
59
+ dcicutils/structured_data.py,sha256=mWjH6h9ARUvYMHI4ZiwbaoKtoeM0CAOz1UxCHh4HIHE,32874
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.1b4.dist-info/LICENSE.txt,sha256=t0_-jIjqxNnymZoNJe-OltRIuuF8qfhN0ATlHyrUJPk,1102
66
- dcicutils-8.5.0.1b4.dist-info/METADATA,sha256=Zpf8fTsgsuRfo8WDGkONHxtcf4SPWOFK_4iCNVAhB78,3314
67
- dcicutils-8.5.0.1b4.dist-info/WHEEL,sha256=7Z8_27uaHI_UZAc4Uox4PpBhQ9Y5_modZXWMxtUi4NU,88
68
- dcicutils-8.5.0.1b4.dist-info/entry_points.txt,sha256=8wbw5csMIgBXhkwfgsgJeuFcoUc0WsucUxmOyml2aoA,209
69
- dcicutils-8.5.0.1b4.dist-info/RECORD,,
65
+ dcicutils-8.5.0.1b6.dist-info/LICENSE.txt,sha256=t0_-jIjqxNnymZoNJe-OltRIuuF8qfhN0ATlHyrUJPk,1102
66
+ dcicutils-8.5.0.1b6.dist-info/METADATA,sha256=wWiZixknI6Pne33sGS-Lxeh6hSKSScj44tPcctlpHJw,3314
67
+ dcicutils-8.5.0.1b6.dist-info/WHEEL,sha256=7Z8_27uaHI_UZAc4Uox4PpBhQ9Y5_modZXWMxtUi4NU,88
68
+ dcicutils-8.5.0.1b6.dist-info/entry_points.txt,sha256=8wbw5csMIgBXhkwfgsgJeuFcoUc0WsucUxmOyml2aoA,209
69
+ dcicutils-8.5.0.1b6.dist-info/RECORD,,