From 20c865080b3204389f8d745aa593bac256c697a0 Mon Sep 17 00:00:00 2001 From: "John T. Wodder II" Date: Mon, 10 Aug 2020 17:10:51 -0400 Subject: [PATCH 01/11] [GH-184] Add a get_instance() function --- dandi/utils.py | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++ setup.cfg | 3 +- 2 files changed, 77 insertions(+), 1 deletion(-) diff --git a/dandi/utils.py b/dandi/utils.py index 67bb90b50..21065b01a 100644 --- a/dandi/utils.py +++ b/dandi/utils.py @@ -11,8 +11,13 @@ from pathlib import Path +from packaging.version import Version +import requests import ruamel.yaml +from . import __version__ +from .consts import dandi_instance, known_instances, known_instances_rev + if sys.version_info[:2] < (3, 7): import dateutil.parser @@ -504,3 +509,73 @@ def delayed(*args, **kwargs): import joblib return joblib.delayed(*args, **kwargs) + + +def get_instance(dandi_instance_id): + if dandi_instance_id.lower().startswith(("http://", "https://")): + redirector_url = dandi_instance_id + dandi_id = known_instances_rev.get(redirector_url) + if dandi_id is not None: + instance = known_instances[dandi_id] + else: + instance = None + else: + instance = known_instances[dandi_instance_id] + redirector_url = instance.redirector + if redirector_url is None: + raise ValueError("DANDI instance has no known redirector URL") + try: + r = requests.get(f"{redirector_url}/server-info") + r.raise_for_status() + except Exception as e: + lgr.warning("Request to %s failed (%s)", redirector_url, str(e)) + if instance is not None: + lgr.warning("Using hard-coded URLs") + return instance + else: + raise RuntimeError( + f"Could not retrieve server info from {redirector_url}," + " and client does not recognize URL" + ) + server_info = r.json() + minversion = Version(server_info["cli-minimal-version"]) + bad_versions = [Version(v) for v in server_info["cli-bad-versions"]] + our_version = Version(__version__) + if our_version < minversion: + raise CliVersionTooLowError(our_version, minversion, bad_versions) + if our_version in bad_versions: + raise BadCliVersionError(our_version, minversion, bad_versions) + return dandi_instance( + girder=server_info["services"]["girder"], + gui=server_info["services"]["webui"], + redirector=redirector_url, + ) + + +class CliVersionError(Exception): + def __init__(self, our_version, minversion, bad_versions): + self.our_version = our_version + self.minversion = minversion + self.bad_versions = bad_versions + + def server_requirements(self): + s = f"Server requires at least version {self.minversion}" + if self.bad_versions: + s += f" (but not {', '.join(map(str, self.bad_versions))})" + return s + + +class CliVersionTooLowError(CliVersionError): + def __str__(self): + return ( + f"Client version {self.our_version} is too low! " + + self.server_requirements() + ) + + +class BadCliVersionError(CliVersionError): + def __str__(self): + return ( + f"Client version {self.our_version} is rejected by server! " + + self.server_requirements() + ) diff --git a/setup.cfg b/setup.cfg index 25b9f50ef..240662175 100644 --- a/setup.cfg +++ b/setup.cfg @@ -42,12 +42,14 @@ install_requires = joblib pyout humanize + requests ~= 2.20 ruamel.yaml >=0.15, <1 keyring keyrings.alt python-dateutil; python_version < "3.7" semantic-version tqdm + packaging zip_safe = False packages = find: include_package_data = True @@ -70,7 +72,6 @@ test = mock pytest pytest-cov - requests ~= 2.20 all = #%(doc)s %(extensions)s From 2aa0aea53c29f423bc8e432e8b57b0d49317a47e Mon Sep 17 00:00:00 2001 From: "John T. Wodder II" Date: Tue, 11 Aug 2020 12:47:05 -0400 Subject: [PATCH 02/11] Use semantic_version instead of packaging --- dandi/utils.py | 2 +- setup.cfg | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/dandi/utils.py b/dandi/utils.py index 21065b01a..6a2641ad2 100644 --- a/dandi/utils.py +++ b/dandi/utils.py @@ -11,9 +11,9 @@ from pathlib import Path -from packaging.version import Version import requests import ruamel.yaml +from semantic_version import Version from . import __version__ from .consts import dandi_instance, known_instances, known_instances_rev diff --git a/setup.cfg b/setup.cfg index 240662175..69666d38e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -49,7 +49,6 @@ install_requires = python-dateutil; python_version < "3.7" semantic-version tqdm - packaging zip_safe = False packages = find: include_package_data = True From 431bb0a882bd0dcd1c0e0da71c6f5d484d8af801 Mon Sep 17 00:00:00 2001 From: "John T. Wodder II" Date: Tue, 11 Aug 2020 12:50:44 -0400 Subject: [PATCH 03/11] Move CLI version exceptions to dandi/exceptions.py --- dandi/exceptions.py | 31 +++++++++++++++++++++++++++++++ dandi/utils.py | 30 +----------------------------- 2 files changed, 32 insertions(+), 29 deletions(-) diff --git a/dandi/exceptions.py b/dandi/exceptions.py index ce64b587d..39ea31739 100644 --- a/dandi/exceptions.py +++ b/dandi/exceptions.py @@ -23,3 +23,34 @@ class FailedToConnectError(RuntimeError): """Failed to connect to online resource""" pass + + +class CliVersionError(RuntimeError): + """ Base class for `CliVersionTooLowError` and `BadCliVersionError` """ + + def __init__(self, our_version, minversion, bad_versions): + self.our_version = our_version + self.minversion = minversion + self.bad_versions = bad_versions + + def server_requirements(self): + s = f"Server requires at least version {self.minversion}" + if self.bad_versions: + s += f" (but not {', '.join(map(str, self.bad_versions))})" + return s + + +class CliVersionTooLowError(CliVersionError): + def __str__(self): + return ( + f"Client version {self.our_version} is too low! " + + self.server_requirements() + ) + + +class BadCliVersionError(CliVersionError): + def __str__(self): + return ( + f"Client version {self.our_version} is rejected by server! " + + self.server_requirements() + ) diff --git a/dandi/utils.py b/dandi/utils.py index 6a2641ad2..f91ed12de 100644 --- a/dandi/utils.py +++ b/dandi/utils.py @@ -17,6 +17,7 @@ from . import __version__ from .consts import dandi_instance, known_instances, known_instances_rev +from .exceptions import BadCliVersionError, CliVersionTooLowError if sys.version_info[:2] < (3, 7): import dateutil.parser @@ -550,32 +551,3 @@ def get_instance(dandi_instance_id): gui=server_info["services"]["webui"], redirector=redirector_url, ) - - -class CliVersionError(Exception): - def __init__(self, our_version, minversion, bad_versions): - self.our_version = our_version - self.minversion = minversion - self.bad_versions = bad_versions - - def server_requirements(self): - s = f"Server requires at least version {self.minversion}" - if self.bad_versions: - s += f" (but not {', '.join(map(str, self.bad_versions))})" - return s - - -class CliVersionTooLowError(CliVersionError): - def __str__(self): - return ( - f"Client version {self.our_version} is too low! " - + self.server_requirements() - ) - - -class BadCliVersionError(CliVersionError): - def __str__(self): - return ( - f"Client version {self.our_version} is rejected by server! " - + self.server_requirements() - ) From d226fe8ac14668aca61132f05fbc315a6958f3ba Mon Sep 17 00:00:00 2001 From: "John T. Wodder II" Date: Tue, 11 Aug 2020 12:53:31 -0400 Subject: [PATCH 04/11] =?UTF-8?q?CliVersionTooLowError=20=E2=86=92=20CliVe?= =?UTF-8?q?rsionTooOldError?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dandi/exceptions.py | 6 +++--- dandi/utils.py | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/dandi/exceptions.py b/dandi/exceptions.py index 39ea31739..3195d53e6 100644 --- a/dandi/exceptions.py +++ b/dandi/exceptions.py @@ -26,7 +26,7 @@ class FailedToConnectError(RuntimeError): class CliVersionError(RuntimeError): - """ Base class for `CliVersionTooLowError` and `BadCliVersionError` """ + """ Base class for `CliVersionTooOldError` and `BadCliVersionError` """ def __init__(self, our_version, minversion, bad_versions): self.our_version = our_version @@ -40,10 +40,10 @@ def server_requirements(self): return s -class CliVersionTooLowError(CliVersionError): +class CliVersionTooOldError(CliVersionError): def __str__(self): return ( - f"Client version {self.our_version} is too low! " + f"Client version {self.our_version} is too old! " + self.server_requirements() ) diff --git a/dandi/utils.py b/dandi/utils.py index f91ed12de..2cf00b0c6 100644 --- a/dandi/utils.py +++ b/dandi/utils.py @@ -17,7 +17,7 @@ from . import __version__ from .consts import dandi_instance, known_instances, known_instances_rev -from .exceptions import BadCliVersionError, CliVersionTooLowError +from .exceptions import BadCliVersionError, CliVersionTooOldError if sys.version_info[:2] < (3, 7): import dateutil.parser @@ -543,7 +543,7 @@ def get_instance(dandi_instance_id): bad_versions = [Version(v) for v in server_info["cli-bad-versions"]] our_version = Version(__version__) if our_version < minversion: - raise CliVersionTooLowError(our_version, minversion, bad_versions) + raise CliVersionTooOldError(our_version, minversion, bad_versions) if our_version in bad_versions: raise BadCliVersionError(our_version, minversion, bad_versions) return dandi_instance( From 08f7fb1686865edcf14058dff1090c5850b52a1a Mon Sep 17 00:00:00 2001 From: "John T. Wodder II" Date: Tue, 11 Aug 2020 13:23:32 -0400 Subject: [PATCH 05/11] Test get_instance() --- dandi/tests/test_utils.py | 147 ++++++++++++++++++++++++++++++++++++++ dandi/utils.py | 6 +- setup.cfg | 1 + 3 files changed, 151 insertions(+), 3 deletions(-) diff --git a/dandi/tests/test_utils.py b/dandi/tests/test_utils.py index 8347521d3..0d1f08c67 100644 --- a/dandi/tests/test_utils.py +++ b/dandi/tests/test_utils.py @@ -3,12 +3,17 @@ import time import datetime import pytest +import responses +from .. import __version__ +from ..consts import dandi_instance, known_instances +from ..exceptions import BadCliVersionError, CliVersionTooOldError from ..utils import ( ensure_datetime, ensure_strtime, find_files, flatten, flattened, + get_instance, get_utcnow_datetime, is_same_time, on_windows, @@ -122,3 +127,145 @@ def test_flatten(): 0, 1, ] + + +@responses.activate +def test_get_instance_dandi(): + responses.add( + responses.GET, + "https://dandiarchive.org/server-info", + json={ + "version": "1.0.0", + "cli-minimal-version": "0.5.0", + "cli-bad-versions": [], + "services": { + "girder": {"url": "https://girder.dandi"}, + "webui": {"url": "https://gui.dandi"}, + "api": {"url": "https://publish.dandi/api"}, + "jupyterhub": {"url": "https://hub.dandi"}, + }, + }, + ) + assert get_instance("dandi") == dandi_instance( + girder="https://girder.dandi", + gui="https://gui.dandi", + redirector="https://dandiarchive.org", + ) + + +@responses.activate +def test_get_instance_url(): + responses.add( + responses.GET, + "https://example.dandi/server-info", + json={ + "version": "1.0.0", + "cli-minimal-version": "0.5.0", + "cli-bad-versions": [], + "services": { + "girder": {"url": "https://girder.dandi"}, + "webui": {"url": "https://gui.dandi"}, + "api": {"url": "https://publish.dandi/api"}, + "jupyterhub": {"url": "https://hub.dandi"}, + }, + }, + ) + assert get_instance("https://example.dandi/") == dandi_instance( + girder="https://girder.dandi", + gui="https://gui.dandi", + redirector="https://example.dandi/", + ) + + +@responses.activate +def test_get_instance_cli_version_too_old(): + responses.add( + responses.GET, + "https://example.dandi/server-info", + json={ + "version": "1.0.0", + "cli-minimal-version": "99.99.99", + "cli-bad-versions": [], + "services": { + "girder": {"url": "https://girder.dandi"}, + "webui": {"url": "https://gui.dandi"}, + "api": {"url": "https://publish.dandi/api"}, + "jupyterhub": {"url": "https://hub.dandi"}, + }, + }, + ) + with pytest.raises(CliVersionTooOldError) as excinfo: + get_instance("https://example.dandi/") + assert str(excinfo.value) == ( + f"Client version {__version__} is too old!" + " Server requires at least version 99.99.99" + ) + + +@responses.activate +def test_get_instance_bad_cli_version(): + responses.add( + responses.GET, + "https://example.dandi/server-info", + json={ + "version": "1.0.0", + "cli-minimal-version": "0.5.0", + "cli-bad-versions": [__version__], + "services": { + "girder": {"url": "https://girder.dandi"}, + "webui": {"url": "https://gui.dandi"}, + "api": {"url": "https://publish.dandi/api"}, + "jupyterhub": {"url": "https://hub.dandi"}, + }, + }, + ) + with pytest.raises(BadCliVersionError) as excinfo: + get_instance("https://example.dandi/") + assert str(excinfo.value) == ( + f"Client version {__version__} is rejected by server!" + f" Server requires at least version 0.5.0 (but not {__version__})" + ) + + +@responses.activate +def test_get_instance_id_bad_response(): + responses.add( + responses.GET, + "https://dandiarchive.org/server-info", + body="404 -- not found", + status=404, + ) + assert get_instance("dandi") is known_instances["dandi"] + + +@responses.activate +def test_get_instance_known_url_bad_response(): + responses.add( + responses.GET, + "https://dandiarchive.org/server-info", + body="404 -- not found", + status=404, + ) + assert get_instance("https://dandiarchive.org") is known_instances["dandi"] + + +@responses.activate +def test_get_instance_unknown_url_bad_response(): + responses.add( + responses.GET, + "https://dandi.nil/server-info", + body="404 -- not found", + status=404, + ) + with pytest.raises(RuntimeError) as excinfo: + get_instance("https://dandi.nil") + assert str(excinfo.value) == ( + "Could not retrieve server info from https://dandi.nil," + " and client does not recognize URL" + ) + + +def test_get_instance_id_no_redirector(): + with pytest.raises(ValueError) as excinfo: + get_instance("local-girder-only") + assert str(excinfo.value) == "DANDI instance has no known redirector URL" diff --git a/dandi/utils.py b/dandi/utils.py index 2cf00b0c6..5f4758ca8 100644 --- a/dandi/utils.py +++ b/dandi/utils.py @@ -526,7 +526,7 @@ def get_instance(dandi_instance_id): if redirector_url is None: raise ValueError("DANDI instance has no known redirector URL") try: - r = requests.get(f"{redirector_url}/server-info") + r = requests.get(redirector_url.rstrip("/") + "/server-info") r.raise_for_status() except Exception as e: lgr.warning("Request to %s failed (%s)", redirector_url, str(e)) @@ -547,7 +547,7 @@ def get_instance(dandi_instance_id): if our_version in bad_versions: raise BadCliVersionError(our_version, minversion, bad_versions) return dandi_instance( - girder=server_info["services"]["girder"], - gui=server_info["services"]["webui"], + girder=server_info["services"]["girder"]["url"], + gui=server_info["services"]["webui"]["url"], redirector=redirector_url, ) diff --git a/setup.cfg b/setup.cfg index 69666d38e..8f35e17fa 100644 --- a/setup.cfg +++ b/setup.cfg @@ -71,6 +71,7 @@ test = mock pytest pytest-cov + responses all = #%(doc)s %(extensions)s From 7efdbd43c009d4d72d516ed1f0435ebed405c537 Mon Sep 17 00:00:00 2001 From: "John T. Wodder II" Date: Tue, 11 Aug 2020 13:42:27 -0400 Subject: [PATCH 06/11] Replace some occurrences of known_instances with get_instance() --- dandi/download.py | 6 ++---- dandi/register.py | 5 +++-- dandi/upload.py | 5 ++--- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/dandi/download.py b/dandi/download.py index b3cd295a5..40b7ce1f5 100644 --- a/dandi/download.py +++ b/dandi/download.py @@ -6,7 +6,7 @@ from .consts import dandiset_metadata_file, known_instances, metadata_digests from .dandiset import Dandiset from .exceptions import FailedToConnectError, NotFoundError, UnknownURLError -from .utils import flatten, flattened, Parallel, delayed +from .utils import flatten, flattened, Parallel, delayed, get_instance lgr = get_logger() @@ -121,9 +121,7 @@ def parse(cls, url, *, map_instance=True): settings["map_instance"], ", ".join(known_instances) ) ) - return (known_instances[settings["map_instance"]].girder,) + tuple( - _ - ) + return (get_instance(settings["map_instance"]).girder,) + tuple(_) continue # in this run we ignore an match further else: break diff --git a/dandi/register.py b/dandi/register.py index 870304898..6b4c3d9b6 100644 --- a/dandi/register.py +++ b/dandi/register.py @@ -3,14 +3,15 @@ from . import get_logger from . import girder -from .consts import dandiset_metadata_file, known_instances, routes +from .consts import dandiset_metadata_file, routes from .dandiset import Dandiset +from .utils import get_instance lgr = get_logger() def register(name, description, dandiset_path=None, dandi_instance="dandi"): - dandi_instance = known_instances[dandi_instance] + dandi_instance = get_instance(dandi_instance) if not dandiset_path and op.exists(dandiset_metadata_file): dandiset = Dandiset.find(os.getcwd()) if dandiset: diff --git a/dandi/upload.py b/dandi/upload.py index edac0c7c2..ce40ec85c 100644 --- a/dandi/upload.py +++ b/dandi/upload.py @@ -8,12 +8,11 @@ from .cli.command import lgr from . import __version__ -from .utils import ensure_datetime, ensure_strtime +from .utils import ensure_datetime, ensure_strtime, get_instance from .consts import ( collection_drafts, dandiset_identifier_regex, dandiset_metadata_file, - known_instances, metadata_digests, ) @@ -91,7 +90,7 @@ def upload( ignore_benign_pynwb_warnings() # so validate doesn't whine - client = girder.get_client(known_instances[dandi_instance].girder) + client = girder.get_client(get_instance(dandi_instance).girder) try: collection_rec = girder.ensure_collection(client, girder_collection) From 2889208d9a16972d915cd8b0113bb3a60f7e70f5 Mon Sep 17 00:00:00 2001 From: "John T. Wodder II" Date: Tue, 11 Aug 2020 13:57:45 -0400 Subject: [PATCH 07/11] Fetch all commits in test workflow --- .github/workflows/test.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4a8ce44d4..506d3d2ac 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -25,8 +25,10 @@ jobs: steps: - name: Set up environment uses: actions/checkout@v1 - with: # no need for the history - fetch-depth: 1 + with: + # Fetch all commits so that versioneer will return something compatible + # with semantic-version + fetch-depth: 0 - name: Set up Python ${{ matrix.python }} uses: actions/setup-python@v1 with: From 68743258fc26d3bef675a3c1e82b9cbbd0598d9b Mon Sep 17 00:00:00 2001 From: "John T. Wodder II" Date: Tue, 11 Aug 2020 15:15:32 -0400 Subject: [PATCH 08/11] Make pytest ignore DeprecationWarnings from responses --- tox.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/tox.ini b/tox.ini index be8222d45..1bf601172 100644 --- a/tox.ini +++ b/tox.ini @@ -23,6 +23,7 @@ filterwarnings = error ignore:No cached namespaces found .*:UserWarning ignore:ignoring namespace '.*' because it already exists:UserWarning + ignore::DeprecationWarning:responses [coverage:run] parallel = True From 1cf0d70afbc805718d9a007634176011fa74182e Mon Sep 17 00:00:00 2001 From: "John T. Wodder II" Date: Wed, 12 Aug 2020 09:31:19 -0400 Subject: [PATCH 09/11] Make redirector report http://localhost:8081 as Girder URL --- dandi/tests/data/dandiarchive-docker/docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dandi/tests/data/dandiarchive-docker/docker-compose.yml b/dandi/tests/data/dandiarchive-docker/docker-compose.yml index ef0a109c3..5b825e21f 100644 --- a/dandi/tests/data/dandiarchive-docker/docker-compose.yml +++ b/dandi/tests/data/dandiarchive-docker/docker-compose.yml @@ -42,7 +42,7 @@ services: ports: - "8079:8080" environment: - GIRDER_URL: http://girder:8080 + GIRDER_URL: http://localhost:8081 GUI_URL: http://localhost:8086 ABOUT_URL: http://www.dandiarchive.org From 389a19a176554ca4936d8168f4a487f8b4478401 Mon Sep 17 00:00:00 2001 From: "John T. Wodder II" Date: Wed, 12 Aug 2020 09:44:09 -0400 Subject: [PATCH 10/11] Raise helpful error if /server-info returns invalid version --- dandi/tests/test_utils.py | 26 ++++++++++++++++++++++++++ dandi/utils.py | 10 ++++++++-- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/dandi/tests/test_utils.py b/dandi/tests/test_utils.py index 0d1f08c67..f247c4c9a 100644 --- a/dandi/tests/test_utils.py +++ b/dandi/tests/test_utils.py @@ -269,3 +269,29 @@ def test_get_instance_id_no_redirector(): with pytest.raises(ValueError) as excinfo: get_instance("local-girder-only") assert str(excinfo.value) == "DANDI instance has no known redirector URL" + + +@responses.activate +def test_get_instance_bad_version_from_server(): + responses.add( + responses.GET, + "https://example.dandi/server-info", + json={ + "version": "1.0.0", + "cli-minimal-version": "foobar", + "cli-bad-versions": [], + "services": { + "girder": {"url": "https://girder.dandi"}, + "webui": {"url": "https://gui.dandi"}, + "api": {"url": "https://publish.dandi/api"}, + "jupyterhub": {"url": "https://hub.dandi"}, + }, + }, + ) + with pytest.raises(ValueError) as excinfo: + get_instance("https://example.dandi/") + assert str(excinfo.value).startswith( + "https://example.dandi/ returned an incorrectly formatted version;" + " please contact that server's administrators: " + ) + assert "foobar" in str(excinfo.value) diff --git a/dandi/utils.py b/dandi/utils.py index 5f4758ca8..501265ad3 100644 --- a/dandi/utils.py +++ b/dandi/utils.py @@ -539,8 +539,14 @@ def get_instance(dandi_instance_id): " and client does not recognize URL" ) server_info = r.json() - minversion = Version(server_info["cli-minimal-version"]) - bad_versions = [Version(v) for v in server_info["cli-bad-versions"]] + try: + minversion = Version(server_info["cli-minimal-version"]) + bad_versions = [Version(v) for v in server_info["cli-bad-versions"]] + except ValueError as e: + raise ValueError( + f"{redirector_url} returned an incorrectly formatted version;" + f" please contact that server's administrators: {e}" + ) our_version = Version(__version__) if our_version < minversion: raise CliVersionTooOldError(our_version, minversion, bad_versions) From cf73932905d199ebc71bcb40f69256ed8e9b8c60 Mon Sep 17 00:00:00 2001 From: "John T. Wodder II" Date: Wed, 12 Aug 2020 09:50:50 -0400 Subject: [PATCH 11/11] get_instance(): Immediately return known instances that lack redirector URLs --- dandi/tests/test_utils.py | 4 +--- dandi/utils.py | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/dandi/tests/test_utils.py b/dandi/tests/test_utils.py index f247c4c9a..6fc828411 100644 --- a/dandi/tests/test_utils.py +++ b/dandi/tests/test_utils.py @@ -266,9 +266,7 @@ def test_get_instance_unknown_url_bad_response(): def test_get_instance_id_no_redirector(): - with pytest.raises(ValueError) as excinfo: - get_instance("local-girder-only") - assert str(excinfo.value) == "DANDI instance has no known redirector URL" + assert get_instance("local-girder-only") is known_instances["local-girder-only"] @responses.activate diff --git a/dandi/utils.py b/dandi/utils.py index 501265ad3..b6b26e55a 100644 --- a/dandi/utils.py +++ b/dandi/utils.py @@ -524,7 +524,7 @@ def get_instance(dandi_instance_id): instance = known_instances[dandi_instance_id] redirector_url = instance.redirector if redirector_url is None: - raise ValueError("DANDI instance has no known redirector URL") + return instance try: r = requests.get(redirector_url.rstrip("/") + "/server-info") r.raise_for_status()