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 arguments for API query parameters when fetching all Dandisets; support creating embargoed Dandisets #1414

Merged
merged 3 commits into from
Feb 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 70 additions & 6 deletions dandi/dandiapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -554,19 +554,83 @@
return d.for_version(version_id)
return d

def get_dandisets(self) -> Iterator[RemoteDandiset]:
def get_dandisets(
self,
*,
draft: bool | None = None,
embargoed: bool | None = None,
empty: bool | None = None,
mine: bool | None = None,
order: str | None = None,
search: str | None = None,
) -> Iterator[RemoteDandiset]:
"""
Returns a generator of all Dandisets on the server. For each Dandiset,
the `RemoteDandiset`'s version is set to the most recent published
version if there is one, otherwise to the draft version.
"""
for data in self.paginate("/dandisets/"):

.. versionchanged:: 0.61.0

``draft``, ``embargoed``, ``empty``, ``mine``, ``order``, and
``search`` parameters added

:param draft:
If true, Dandisets that have only draft versions (i.e., that
haven't yet been published) will be included in the results
(default true)

:param embargoed:
If true, embargoed Dandisets will be included in the results
(default false)

:param empty:
If true, empty Dandisets will be included in the results (default
true)

:param mine:
If true, only Dandisets owned by the authenticated user will be
retrieved (default false)

:param order:
The field to sort the results by. The accepted field names are
``"id"``, ``"name"``, ``"modified"``, and ``"size"``. Prepend a
hyphen to the field name to reverse the sort order.

:param search:
A search string to filter the returned Dandisets by. The string is
searched for in the metadata of Dandiset versions.
"""
for data in self.paginate(

Check warning on line 603 in dandi/dandiapi.py

View check run for this annotation

Codecov / codecov/patch

dandi/dandiapi.py#L603

Added line #L603 was not covered by tests
"/dandisets/",
params={
"draft": draft,
"embargoed": embargoed,
"empty": empty,
"ordering": order,
"search": search,
"user": "me" if mine else None,
yarikoptic marked this conversation as resolved.
Show resolved Hide resolved
},
):
yarikoptic marked this conversation as resolved.
Show resolved Hide resolved
yield RemoteDandiset.from_data(self, data)

def create_dandiset(self, name: str, metadata: dict[str, Any]) -> RemoteDandiset:
"""Creates a Dandiset with the given name & metadata"""
def create_dandiset(
self, name: str, metadata: dict[str, Any], *, embargo: bool = False
) -> RemoteDandiset:
"""
Creates a Dandiset with the given name & metadata. If ``embargo`` is
`True`, the resulting Dandiset will be embargoed.

.. versionchanged:: 0.61.0

``embargo`` argument added
"""
return RemoteDandiset.from_data(
self, self.post("/dandisets/", json={"name": name, "metadata": metadata})
self,
self.post(
"/dandisets/",
json={"name": name, "metadata": metadata},
params={"embargo": "true" if embargo else "false"},
),
)

def check_schema_version(self, schema_version: str | None = None) -> None:
Expand Down
3 changes: 2 additions & 1 deletion dandi/tests/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,7 @@ class SampleDandisetFactory:
local_dandi_api: DandiAPI
tmp_path_factory: pytest.TempPathFactory

def mkdandiset(self, name: str) -> SampleDandiset:
def mkdandiset(self, name: str, embargo: bool = False) -> SampleDandiset:
d = self.local_dandi_api.client.create_dandiset(
name,
# Minimal metadata needed to create a publishable Dandiset:
Expand All @@ -539,6 +539,7 @@ def mkdandiset(self, name: str) -> SampleDandiset:
}
],
},
embargo=embargo,
)
dspath = self.tmp_path_factory.mktemp("dandiset")
(dspath / dandiset_metadata_file).write_text(f"identifier: '{d.identifier}'\n")
Expand Down
44 changes: 42 additions & 2 deletions dandi/tests/test_dandiapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import requests
import responses

from .fixtures import DandiAPI, SampleDandiset
from .fixtures import DandiAPI, SampleDandiset, SampleDandisetFactory
from .skip import mark
from .. import dandiapi
from ..consts import (
Expand Down Expand Up @@ -329,7 +329,47 @@

def test_get_dandisets(text_dandiset: SampleDandiset) -> None:
dandisets = list(text_dandiset.client.get_dandisets())
assert sum(1 for d in dandisets if d.identifier == text_dandiset.dandiset_id) == 1
assert text_dandiset.dandiset_id in [d.identifier for d in dandisets]

Check warning on line 332 in dandi/tests/test_dandiapi.py

View check run for this annotation

Codecov / codecov/patch

dandi/tests/test_dandiapi.py#L332

Added line #L332 was not covered by tests


def test_get_embargoed_dandisets(
sample_dandiset_factory: SampleDandisetFactory,
) -> None:
ds = sample_dandiset_factory.mkdandiset("Embargoed Dandiset", embargo=True)
dandisets = list(ds.client.get_dandisets(embargoed=True))
assert ds.dandiset_id in [d.identifier for d in dandisets]
dandisets = list(ds.client.get_dandisets(embargoed=False))
assert ds.dandiset_id not in [d.identifier for d in dandisets]
dandisets = list(ds.client.get_dandisets(embargoed=None))
assert ds.dandiset_id not in [d.identifier for d in dandisets]

Check warning on line 344 in dandi/tests/test_dandiapi.py

View check run for this annotation

Codecov / codecov/patch

dandi/tests/test_dandiapi.py#L338-L344

Added lines #L338 - L344 were not covered by tests


def test_get_draft_dandisets(new_dandiset: SampleDandiset) -> None:
dandisets = list(new_dandiset.client.get_dandisets(draft=True))
assert new_dandiset.dandiset_id in [d.identifier for d in dandisets]
dandisets = list(new_dandiset.client.get_dandisets(draft=False))
assert new_dandiset.dandiset_id not in [d.identifier for d in dandisets]
dandisets = list(new_dandiset.client.get_dandisets(draft=None))
assert new_dandiset.dandiset_id in [d.identifier for d in dandisets]

Check warning on line 353 in dandi/tests/test_dandiapi.py

View check run for this annotation

Codecov / codecov/patch

dandi/tests/test_dandiapi.py#L348-L353

Added lines #L348 - L353 were not covered by tests


def test_get_empty_dandisets(new_dandiset: SampleDandiset) -> None:
dandisets = list(new_dandiset.client.get_dandisets(empty=True))
assert new_dandiset.dandiset_id in [d.identifier for d in dandisets]
dandisets = list(new_dandiset.client.get_dandisets(empty=False))
assert new_dandiset.dandiset_id not in [d.identifier for d in dandisets]
dandisets = list(new_dandiset.client.get_dandisets(empty=None))
assert new_dandiset.dandiset_id in [d.identifier for d in dandisets]

Check warning on line 362 in dandi/tests/test_dandiapi.py

View check run for this annotation

Codecov / codecov/patch

dandi/tests/test_dandiapi.py#L357-L362

Added lines #L357 - L362 were not covered by tests


def test_search_get_dandisets(
sample_dandiset_factory: SampleDandisetFactory,
) -> None:
ds = sample_dandiset_factory.mkdandiset("Unicorn Dandiset")
dandisets = list(ds.client.get_dandisets(search="Unicorn"))
assert ds.dandiset_id in [d.identifier for d in dandisets]
dandisets = list(ds.client.get_dandisets(search="Dragon"))
assert ds.dandiset_id not in [d.identifier for d in dandisets]

Check warning on line 372 in dandi/tests/test_dandiapi.py

View check run for this annotation

Codecov / codecov/patch

dandi/tests/test_dandiapi.py#L368-L372

Added lines #L368 - L372 were not covered by tests


def test_get_dandiset_lazy(
Expand Down