Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a get_instance() function #186

Merged
merged 11 commits into from
Aug 12, 2020
75 changes: 75 additions & 0 deletions dandi/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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"])
yarikoptic marked this conversation as resolved.
Show resolved Hide resolved
bad_versions = [Version(v) for v in server_info["cli-bad-versions"]]
yarikoptic marked this conversation as resolved.
Show resolved Hide resolved
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):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's centralize exception definitions in dandi.exceptions. I would probably subclass from RuntimeError instead of a generic Exception

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably worth adding a docstring (or make __str__ explicitly an @abc.abstractmethod) to note that this is just a base exception, without __str__ and thus derived classes should be used

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

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):
yarikoptic marked this conversation as resolved.
Show resolved Hide resolved
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()
)
3 changes: 2 additions & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -70,7 +72,6 @@ test =
mock
pytest
pytest-cov
requests ~= 2.20
all =
#%(doc)s
%(extensions)s
Expand Down