dcicutils 8.5.0.1b6__tar.gz → 8.5.0.1b7__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/PKG-INFO +1 -1
  2. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/portal_utils.py +90 -64
  3. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/structured_data.py +3 -6
  4. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/pyproject.toml +1 -1
  5. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/LICENSE.txt +0 -0
  6. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/README.rst +0 -0
  7. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/__init__.py +0 -0
  8. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/base.py +0 -0
  9. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/beanstalk_utils.py +0 -0
  10. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/bundle_utils.py +0 -0
  11. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/cloudformation_utils.py +0 -0
  12. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/codebuild_utils.py +0 -0
  13. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/command_utils.py +0 -0
  14. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/common.py +0 -0
  15. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/contribution_scripts.py +0 -0
  16. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/contribution_utils.py +0 -0
  17. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/creds_utils.py +0 -0
  18. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/data_readers.py +0 -0
  19. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/data_utils.py +0 -0
  20. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/deployment_utils.py +0 -0
  21. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/diff_utils.py +0 -0
  22. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/docker_utils.py +0 -0
  23. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/ecr_scripts.py +0 -0
  24. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/ecr_utils.py +0 -0
  25. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/ecs_utils.py +0 -0
  26. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/env_base.py +0 -0
  27. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/env_manager.py +0 -0
  28. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/env_scripts.py +0 -0
  29. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/env_utils.py +0 -0
  30. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/env_utils_legacy.py +0 -0
  31. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/es_utils.py +0 -0
  32. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/exceptions.py +0 -0
  33. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/ff_mocks.py +0 -0
  34. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/ff_utils.py +0 -0
  35. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/function_cache_decorator.py +0 -0
  36. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/glacier_utils.py +0 -0
  37. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/jh_utils.py +0 -0
  38. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/kibana/dashboards.json +0 -0
  39. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/kibana/readme.md +0 -0
  40. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/lang_utils.py +0 -0
  41. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/license_policies/c4-infrastructure.jsonc +0 -0
  42. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/license_policies/c4-python-infrastructure.jsonc +0 -0
  43. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/license_policies/park-lab-common-server.jsonc +0 -0
  44. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/license_policies/park-lab-common.jsonc +0 -0
  45. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/license_policies/park-lab-gpl-pipeline.jsonc +0 -0
  46. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/license_policies/park-lab-pipeline.jsonc +0 -0
  47. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/license_utils.py +0 -0
  48. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/log_utils.py +0 -0
  49. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/misc_utils.py +0 -0
  50. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/obfuscation_utils.py +0 -0
  51. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/opensearch_utils.py +0 -0
  52. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/project_utils.py +0 -0
  53. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/qa_checkers.py +0 -0
  54. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/qa_utils.py +0 -0
  55. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/redis_tools.py +0 -0
  56. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/redis_utils.py +0 -0
  57. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/s3_utils.py +0 -0
  58. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/scripts/publish_to_pypi.py +0 -0
  59. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/scripts/run_license_checker.py +0 -0
  60. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/secrets_utils.py +0 -0
  61. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/sheet_utils.py +0 -0
  62. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/snapshot_utils.py +0 -0
  63. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/ssl_certificate_utils.py +0 -0
  64. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/task_utils.py +0 -0
  65. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/trace_utils.py +0 -0
  66. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/validation_utils.py +0 -0
  67. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/variant_utils.py +0 -0
  68. {dcicutils-8.5.0.1b6 → dcicutils-8.5.0.1b7}/dcicutils/zip_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dcicutils
3
- Version: 8.5.0.1b6
3
+ Version: 8.5.0.1b7
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
@@ -1,13 +1,17 @@
1
1
  from collections import deque
2
2
  import io
3
3
  import json
4
- from pyramid.paster import get_app
5
- from pyramid.router import Router
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, Router, dict, tuple, str]] = None,
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, Router], unspecified: Optional[list] = []) -> None:
76
+ def init_from_vapp(vapp: Union[TestApp, VirtualApp, PyramidRouter], unspecified: Optional[list] = []) -> None:
73
77
  init(unspecified)
74
- self._vapp = Portal._create_testapp(vapp)
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._create_testapp(ini_file)
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, Router)):
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
- response = self._vapp.get(self.url(uri), **self._kwargs(**kwargs))
214
- if response and response.status_code in [301, 302, 303, 307, 308] and follow:
215
- response = response.follow()
216
- return self._response(response)
217
- return requests.get(self.url(uri), allow_redirects=follow, **self._kwargs(**kwargs))
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 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))
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
- if files:
229
- return self._vapp.post(self.url(uri), json or data, upload_files=files, **self._kwargs(**kwargs))
230
- else:
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))
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(ini_file: Optional[str] = None) -> Portal:
329
- if isinstance(ini_file, str):
330
- return Portal(Portal._create_testapp(ini_file))
331
- minimal_ini_for_unit_testing = "[app:app]\nuse = egg:encoded\nsqlalchemy.url = postgresql://dummy\n"
332
- with temporary_file(content=minimal_ini_for_unit_testing, suffix=".ini") as ini_file:
333
- return Portal(Portal._create_testapp(ini_file))
334
-
335
- @staticmethod
336
- def create_for_testing_local(ini_file: Optional[str] = None) -> Portal:
337
- if isinstance(ini_file, str) and ini_file:
338
- return Portal(Portal._create_testapp(ini_file))
339
- minimal_ini_for_testing_local = "\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
- 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 _create_testapp(arg: Union[TestApp, VirtualApp, Router, str] = None, app_name: Optional[str] = None) -> TestApp:
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._create_testapp VirtualApp argument error.")
369
+ raise Exception("Portal._create_vapp VirtualApp argument error.")
368
370
  return arg.wrapped_app
369
- if isinstance(arg, Router):
371
+ if isinstance(arg, PyramidRouter):
370
372
  router = arg
371
- elif isinstance(arg, str) or arg is None:
372
- router = get_app(arg or "development.ini", app_name or "app")
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._create_testapp argument error.")
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()
@@ -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(ini_file: Optional[str] = None, schemas: Optional[List[dict]] = None) -> Portal:
620
- return Portal(PortalBase.create_for_testing(ini_file), schemas=schemas)
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):
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "dcicutils"
3
- version = "8.5.0.1b6" # TODO: To become 8.6.0
3
+ version = "8.5.0.1b7" # 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