diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index a5d36df0a..9a737842e 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -61,7 +61,7 @@ development command line options. variable providing the key for a specific known DANDI instance corresponds to the name of the instance. For example, the environment variable `DANDI_API_KEY` provides the key for the known instance named `dandi` and the environment variable - `EMBER_SANDBOX_API_KEY` provides the key for the known instance named `ember-sandbox`. + `EMBER_DANDI_SANDBOX_API_KEY` provides the key for the known instance named `ember-dandi-sandbox`. I.e., the environment variable name is the capitalized version of the instance's name with "-" replaced by "_" suffixed by "_API_KEY". Providing API keys through environment variables avoids using keyrings, thus making it possible to "temporarily" use another diff --git a/dandi/cli/tests/test_instances.py b/dandi/cli/tests/test_instances.py index 4a9ca5b67..d0df778b9 100644 --- a/dandi/cli/tests/test_instances.py +++ b/dandi/cli/tests/test_instances.py @@ -19,13 +19,10 @@ def test_cmd_instances(monkeypatch): "dandi-sandbox:\n" " api: https://api.sandbox.dandiarchive.org/api\n" " gui: https://sandbox.dandiarchive.org\n" - "dandi-staging:\n" - " api: https://api.sandbox.dandiarchive.org/api\n" - " gui: https://sandbox.dandiarchive.org\n" - "ember:\n" + "ember-dandi:\n" " api: https://api-dandi.emberarchive.org/api\n" " gui: https://dandi.emberarchive.org\n" - "ember-sandbox:\n" + "ember-dandi-sandbox:\n" " api: https://api-dandi-sandbox.emberarchive.org/api\n" " gui: https://apl-setup--ember-dandi-archive.netlify.app/\n" "linc:\n" diff --git a/dandi/consts.py b/dandi/consts.py index 5518d8d38..01723d364 100644 --- a/dandi/consts.py +++ b/dandi/consts.py @@ -123,13 +123,6 @@ def urls(self) -> Iterator[str]: "https://dandiarchive.org", "https://api.dandiarchive.org/api", ), - # Deprecated. Remove early 2026. - # Should come before dandi-sandbox so _rev map does map to sandbox - "dandi-staging": DandiInstance( - "dandi-staging", - "https://sandbox.dandiarchive.org", - "https://api.sandbox.dandiarchive.org/api", - ), "dandi-sandbox": DandiInstance( "dandi-sandbox", "https://sandbox.dandiarchive.org", @@ -150,13 +143,13 @@ def urls(self) -> Iterator[str]: "https://staging.lincbrain.org", "https://staging-api.lincbrain.org/api", ), - "ember": DandiInstance( - "ember", + "ember-dandi": DandiInstance( + "ember-dandi", "https://dandi.emberarchive.org", "https://api-dandi.emberarchive.org/api", ), - "ember-sandbox": DandiInstance( - "ember-sandbox", + "ember-dandi-sandbox": DandiInstance( + "ember-dandi-sandbox", "https://apl-setup--ember-dandi-archive.netlify.app/", "https://api-dandi-sandbox.emberarchive.org/api", ), diff --git a/dandi/dandiarchive.py b/dandi/dandiarchive.py index 9da715faa..1cc7ac5d7 100644 --- a/dandi/dandiarchive.py +++ b/dandi/dandiarchive.py @@ -573,6 +573,10 @@ class _dandi_url_parser: dandiset_id_grp = f"(?P{DANDISET_ID_REGEX})" # Should absorb port and "api/": server_grp = "(?P(?Phttps?)://(?P[^/]+)/(api/)?)" + # Build instance name pattern from known instances to avoid matching unknown patterns + instance_name_pattern = "|".join( + re.escape(name.upper()) for name in known_instances + ) known_urls: list[tuple[re.Pattern[str], dict[str, Any], str]] = [ # List of (regex, settings, display string) triples # @@ -589,13 +593,12 @@ class _dandi_url_parser: # for not only "dandiarchive.org" URLs ( re.compile( - rf"(?PDANDI):" + rf"(?P{instance_name_pattern}):" rf"{dandiset_id_grp}" rf"(/(?P{VERSION_REGEX}))?", - flags=re.I, ), {}, - "DANDI:[/]", + ":[/]", ), ( re.compile(r"https?://gui\.dandiarchive\.org/.*"), diff --git a/dandi/tests/test_dandiapi.py b/dandi/tests/test_dandiapi.py index 29f8119b1..b50640b12 100644 --- a/dandi/tests/test_dandiapi.py +++ b/dandi/tests/test_dandiapi.py @@ -869,7 +869,7 @@ def test_asset_as_readable_open(new_dandiset: SampleDandiset, tmp_path: Path) -> ("dandi", "DANDI_API_KEY"), ("dandi-api-local-docker-tests", "DANDI_API_LOCAL_DOCKER_TESTS_API_KEY"), ("dandi-sandbox", "DANDI_SANDBOX_API_KEY"), - ("ember-sandbox", "EMBER_SANDBOX_API_KEY"), + ("ember-dandi-sandbox", "EMBER_DANDI_SANDBOX_API_KEY"), ], ) def test_get_api_key_env_var(instance_name: str, expected_env_var_name: str) -> None: diff --git a/dandi/tests/test_dandiarchive.py b/dandi/tests/test_dandiarchive.py index 2cbf65752..cc5d988a4 100644 --- a/dandi/tests/test_dandiarchive.py +++ b/dandi/tests/test_dandiarchive.py @@ -108,15 +108,56 @@ version_id="draft", ), ), - # lower cased + # numeric version ( - "dandi:000027/0.210831.2033", + "DANDI:000027/0.210831.2033", DandisetURL( instance=known_instances["dandi"], dandiset_id="000027", version_id="0.210831.2033", ), ), + # Test other instances with short format + ( + "DANDI-SANDBOX:000029", + DandisetURL( + instance=known_instances["dandi-sandbox"], + dandiset_id="000029", + version_id=None, + ), + ), + ( + "LINC:000029", + DandisetURL( + instance=known_instances["linc"], + dandiset_id="000029", + version_id=None, + ), + ), + ( + "LINC:000029/0.210831.2033", + DandisetURL( + instance=known_instances["linc"], + dandiset_id="000029", + version_id="0.210831.2033", + ), + ), + ( + "EMBER-DANDI:000029", + DandisetURL( + instance=known_instances["ember-dandi"], + dandiset_id="000029", + version_id=None, + ), + ), + ( + "EMBER-DANDI-SANDBOX:000029/draft", + DandisetURL( + instance=known_instances["ember-dandi-sandbox"], + dandiset_id="000029", + version_id="draft", + ), + ), ( "http://localhost:8000/api/dandisets/000002/", DandisetURL( diff --git a/dandi/tests/test_helptext.py b/dandi/tests/test_helptext.py index b72062112..7495f319b 100644 --- a/dandi/tests/test_helptext.py +++ b/dandi/tests/test_helptext.py @@ -13,7 +13,7 @@ def get_helptext(command): def test_resource_identifier_helptext(): # The \n chars must be included for correct rendering - correct = "Accepted resource identifier patterns:\n - DANDI:[/]\n" + correct = "Accepted resource identifier patterns:\n - :[/]\n" ls_helptext = get_helptext(['dandi', 'ls']) assert correct in ls_helptext diff --git a/dandi/utils.py b/dandi/utils.py index 93a0e138c..9d77f33cc 100644 --- a/dandi/utils.py +++ b/dandi/utils.py @@ -577,8 +577,8 @@ def get_instance(dandi_instance_id: str | DandiInstance) -> DandiInstance: dandi_id = dandi_instance_id instance = known_instances[dandi_id] if dandi_id == "dandi-staging": - lgr.warning( - "'dandi-staging' DANDI instance identifier is deprecated. " + raise ValueError( + "'dandi-staging' DANDI instance identifier was removed. " "The instance was renamed into 'dandi-sandbox', please use that identifier instead." ) if redirector_url is None: diff --git a/docs/source/cmdline/instances.rst b/docs/source/cmdline/instances.rst index c7c3fd636..69958e731 100644 --- a/docs/source/cmdline/instances.rst +++ b/docs/source/cmdline/instances.rst @@ -22,18 +22,15 @@ Example output: dandi-sandbox: api: https://api.sandbox.dandiarchive.org/api gui: https://sandbox.dandiarchive.org - dandi-staging: - api: https://api.sandbox.dandiarchive.org/api - gui: https://sandbox.dandiarchive.org linc-staging: api: https://staging-api.lincbrain.org/api gui: https://staging.lincbrain.org linc: api: https://api.lincbrain.org/api gui: https://lincbrain.org - ember-sandbox: + ember-dandi-sandbox: api: https://api-dandi-sandbox.emberarchive.org/api gui: https://apl-setup--ember-dandi-archive.netlify.app/ - ember: + ember-dandi: api: https://api-dandi.emberarchive.org/api gui: https://dandi.emberarchive.org diff --git a/docs/source/ref/urls.rst b/docs/source/ref/urls.rst index 8c6811008..d314d6d6a 100644 --- a/docs/source/ref/urls.rst +++ b/docs/source/ref/urls.rst @@ -17,8 +17,10 @@ has one, and its draft version will be used otherwise. (case insensitive; ``version`` cannot be "draft") when it redirects to one of the other URL formats -- :samp:`DANDI:{dandiset-id}[/{version}]` (case insensitive) - — Refers to a Dandiset on the main DANDI Archive instance named "dandi". +- :samp:`{instance-name}:{dandiset-id}[/{version}]` (case insensitive, + where ``instance-name`` is a known DANDI instance such as ``DANDI``, + ``DANDI-SANDBOX``, ``LINC``, ``EMBER``, etc.) + — Refers to a Dandiset on the specified DANDI Archive instance. `parse_dandi_url()` converts this format to a `DandisetURL`. - Any ``https://gui.dandiarchive.org/`` or