diff --git a/dandi/dandiarchive.py b/dandi/dandiarchive.py index 9da715faa..59dbfe34b 100644 --- a/dandi/dandiarchive.py +++ b/dandi/dandiarchive.py @@ -573,6 +573,8 @@ 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) for name in known_instances.keys()) known_urls: list[tuple[re.Pattern[str], dict[str, Any], str]] = [ # List of (regex, settings, display string) triples # @@ -589,13 +591,13 @@ 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_dandiarchive.py b/dandi/tests/test_dandiarchive.py index 2cbf65752..dc4bfa0ee 100644 --- a/dandi/tests/test_dandiarchive.py +++ b/dandi/tests/test_dandiarchive.py @@ -117,6 +117,55 @@ 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, + ), + ), + ( + "dandi-sandbox:000029/draft", + DandisetURL( + instance=known_instances["dandi-sandbox"], + dandiset_id="000029", + version_id="draft", + ), + ), + ( + "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:000029", + DandisetURL( + instance=known_instances["ember"], + dandiset_id="000029", + version_id=None, + ), + ), + ( + "ember-sandbox:000029/draft", + DandisetURL( + instance=known_instances["ember-sandbox"], + dandiset_id="000029", + version_id="draft", + ), + ), ( "http://localhost:8000/api/dandisets/000002/", DandisetURL( 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