Skip to content

Commit 8531562

Browse files
Add limit, offset and include_deleted to show_folder (#494)
* add limit and offset to show_folder * add include_deleted * Simply test subfolder creation Co-authored-by: Nicola Soranzo <nicola.soranzo@gmail.com> * Just use the upstream default values Co-authored-by: Nicola Soranzo <nicola.soranzo@gmail.com> * Revert to loop and drop subfolders variable Co-authored-by: Nicola Soranzo <nicola.soranzo@gmail.com> * add test for include_deleted * Simplify test Co-authored-by: Nicola Soranzo <nicola.soranzo@gmail.com> * Simplify test Co-authored-by: Nicola Soranzo <nicola.soranzo@gmail.com> * test content counts * fix test and add docs * total_rows became available only after galaxyproject/galaxy#10204 * add contents generator * Rename content to content_iter Co-authored-by: Nicola Soranzo <nicola.soranzo@gmail.com> * Use sys.maxsize for iteration Co-authored-by: Nicola Soranzo <nicola.soranzo@gmail.com> * overload show_folder * Apply suggestions from code review Co-authored-by: Nicola Soranzo <nicola.soranzo@gmail.com> * Update bioblend/_tests/TestGalaxyFolders.py Co-authored-by: Nicola Soranzo <nicola.soranzo@gmail.com> * revert accidental change * rewording Co-authored-by: Nicola Soranzo <nicola.soranzo@gmail.com> * return is Iterator * rename limit * finish parameter renaming * more missing renaming --------- Co-authored-by: Nicola Soranzo <nicola.soranzo@gmail.com>
1 parent 716f479 commit 8531562

File tree

2 files changed

+149
-4
lines changed

2 files changed

+149
-4
lines changed

bioblend/_tests/TestGalaxyFolders.py

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33
List,
44
)
55

6-
from . import GalaxyTestBase
6+
from . import (
7+
GalaxyTestBase,
8+
test_util,
9+
)
710

811
FOO_DATA = "foo\nbar\n"
912

@@ -36,6 +39,69 @@ def test_show_folder_contents(self):
3639
assert "metadata" in f2
3740
assert self.name == f2["metadata"]["folder_name"]
3841

42+
@test_util.skip_unless_galaxy("release_21.05")
43+
def test_show_folder_contents_limit(self):
44+
for i in range(12):
45+
self.gi.folders.create_folder(self.folder["id"], f"{self.name} {i}")
46+
47+
# check defaults for limit and offset
48+
f2 = self.gi.folders.show_folder(self.folder["id"], contents=True)
49+
assert len(f2["folder_contents"]) == 10
50+
assert f2["folder_contents"][0]["name"] == f"{self.name} 0"
51+
52+
# check non defaults
53+
f2 = self.gi.folders.show_folder(self.folder["id"], contents=True, limit=1, offset=1)
54+
assert len(f2["folder_contents"]) == 1
55+
assert f2["folder_contents"][0]["name"] == f"{self.name} 1"
56+
57+
@test_util.skip_unless_galaxy("release_21.05")
58+
def test_folder_contents_iter(self):
59+
for i in range(12):
60+
self.gi.folders.create_folder(self.folder["id"], f"{self.name} {i}")
61+
62+
# check defaults for limit and offset
63+
f2 = list(self.gi.folders.contents_iter(self.folder["id"]))
64+
assert len(f2) == 12
65+
assert f2[0]["name"] == f"{self.name} 0"
66+
67+
# check non defaults
68+
f2 = list(self.gi.folders.contents_iter(self.folder["id"], batch_size=1))
69+
assert len(f2) == 12
70+
assert f2[0]["name"] == f"{self.name} 0"
71+
72+
@test_util.skip_unless_galaxy("release_21.01")
73+
def test_show_folder_contents_include_deleted(self):
74+
history = self.gi.histories.create_history(name="Test History")
75+
hda_id = self._test_dataset(history["id"])
76+
77+
# Create 2 library datasets into the library folder
78+
ldda1 = self.gi.libraries.copy_from_dataset(
79+
library_id=self.library["id"], dataset_id=hda_id, folder_id=self.folder["id"], message="Added HDA"
80+
)
81+
ldda2 = self.gi.libraries.copy_from_dataset(
82+
library_id=self.library["id"], dataset_id=hda_id, folder_id=self.folder["id"], message="Added HDA"
83+
)
84+
folder_info = self.gi.folders.show_folder(self.folder["id"], contents=True)
85+
assert len(folder_info["folder_contents"]) == 2
86+
assert folder_info["folder_contents"][0]["type"] == "file"
87+
88+
# Delete the library datasets and check if include_deleted works
89+
self.gi.libraries.delete_library_dataset(self.library["id"], ldda1["id"])
90+
self.gi.libraries.delete_library_dataset(self.library["id"], ldda2["id"], purged=True)
91+
folder_info = self.gi.folders.show_folder(self.folder["id"], contents=True, include_deleted=True)
92+
# check if there are 2 contents and the number is correct
93+
assert len(folder_info["folder_contents"]) == 2
94+
assert folder_info["metadata"]["total_rows"] == 2
95+
96+
folder_info = self.gi.folders.show_folder(self.folder["id"], contents=True)
97+
assert len(folder_info["folder_contents"]) == 0
98+
assert folder_info["metadata"]["total_rows"] == 0
99+
# show folders with contents=False does not respect include_deleted
100+
folder_info = self.gi.folders.show_folder(self.folder["id"])
101+
assert folder_info["item_count"] == 2
102+
103+
self.gi.histories.delete_history(history["id"])
104+
39105
def test_delete_folder(self):
40106
self.sub_folder = self.gi.folders.create_folder(self.folder["id"], self.name)
41107
self.gi.folders.delete_folder(self.sub_folder["id"])

bioblend/galaxy/folders/__init__.py

Lines changed: 82 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@
22
Contains possible interactions with the Galaxy library folders
33
"""
44

5+
import sys
56
from typing import (
67
Any,
78
Dict,
9+
Iterator,
810
List,
911
Literal,
1012
Optional,
13+
overload,
1114
TYPE_CHECKING,
1215
Union,
1316
)
@@ -45,7 +48,31 @@ def create_folder(self, parent_folder_id: str, name: str, description: Optional[
4548
payload["description"] = description
4649
return self._post(payload=payload, id=parent_folder_id)
4750

48-
def show_folder(self, folder_id: str, contents: bool = False) -> Dict[str, Any]:
51+
@overload
52+
def show_folder(
53+
self,
54+
folder_id: str,
55+
contents: Literal[False] = False,
56+
) -> Dict[str, Any]: ...
57+
58+
@overload
59+
def show_folder(
60+
self,
61+
folder_id: str,
62+
contents: Literal[True],
63+
limit: int = 10,
64+
offset: int = 0,
65+
include_deleted: bool = False,
66+
) -> Dict[str, Any]: ...
67+
68+
def show_folder(
69+
self,
70+
folder_id: str,
71+
contents: bool = False,
72+
limit: int = 10,
73+
offset: int = 0,
74+
include_deleted: bool = False,
75+
) -> Dict[str, Any]:
4976
"""
5077
Display information about a folder.
5178
@@ -56,11 +83,63 @@ def show_folder(self, folder_id: str, contents: bool = False) -> Dict[str, Any]:
5683
:param contents: True to get the contents of the folder, rather
5784
than just the folder details.
5885
86+
:type limit: int
87+
:param limit: When ``contents=True``, maximum number of items to return.
88+
89+
:type offset: int
90+
:param contents: When ``contents=True``, number of items to skip. Return
91+
contents starting from item offset+1.
92+
93+
:type include_deleted: bool
94+
:param include_deleted: When ``contents=True``, whether to include
95+
deleted items.
96+
5997
:rtype: dict
60-
:return: dictionary including details of the folder
98+
:return: dictionary including details of the folder.
99+
For contents=False the dict contains infos on the folder.
100+
For contents=True the dict contains the keys "metadata" (a dict with
101+
infos on the folder) and "folder_contents" (a list of dicts with info
102+
on the childs).
103+
104+
Notes: For iterating over folder contents there is also contents_iter.
105+
"""
106+
params = {
107+
"limit": limit,
108+
"offset": offset,
109+
"include_deleted": include_deleted,
110+
}
111+
return self._get(id=folder_id, contents=contents, params=params)
112+
113+
def contents_iter(
114+
self,
115+
folder_id: str,
116+
batch_size: int = 10,
117+
include_deleted: bool = False,
118+
) -> Iterator[Dict[str, Any]]:
61119
"""
120+
Iterate over folder contents.
62121
63-
return self._get(id=folder_id, contents=contents)
122+
:type folder_id: str
123+
:param folder_id: the folder's encoded id, prefixed by 'F'
124+
125+
:type batch_size: int
126+
:param batch_size: Batch size to be used internally.
127+
128+
:type include_deleted: bool
129+
:param include_deleted: Whether to include deleted items.
130+
"""
131+
total_rows = sys.maxsize
132+
params = {
133+
"limit": batch_size,
134+
"offset": 0,
135+
"include_deleted": include_deleted,
136+
}
137+
138+
while params["offset"] <= total_rows:
139+
chunk = self._get(id=folder_id, contents=True, params=params)
140+
total_rows = chunk["metadata"]["total_rows"]
141+
yield from chunk["folder_contents"]
142+
params["offset"] += batch_size
64143

65144
def delete_folder(self, folder_id: str, undelete: bool = False) -> Dict[str, Any]:
66145
"""

0 commit comments

Comments
 (0)