geoseeq 0.7.2__py3-none-any.whl → 0.7.3.dev1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- geoseeq/cli/main.py +54 -36
- geoseeq/dashboard/dashboard.py +183 -25
- geoseeq/project.py +5 -0
- geoseeq/sample.py +83 -15
- {geoseeq-0.7.2.dist-info → geoseeq-0.7.3.dev1.dist-info}/METADATA +10 -5
- {geoseeq-0.7.2.dist-info → geoseeq-0.7.3.dev1.dist-info}/RECORD +9 -9
- {geoseeq-0.7.2.dist-info → geoseeq-0.7.3.dev1.dist-info}/WHEEL +0 -0
- {geoseeq-0.7.2.dist-info → geoseeq-0.7.3.dev1.dist-info}/entry_points.txt +0 -0
- {geoseeq-0.7.2.dist-info → geoseeq-0.7.3.dev1.dist-info}/licenses/LICENSE +0 -0
geoseeq/cli/main.py
CHANGED
@@ -1,35 +1,33 @@
|
|
1
|
-
|
2
1
|
import logging
|
3
2
|
|
4
3
|
import click
|
5
4
|
|
5
|
+
from geoseeq.knex import DEFAULT_ENDPOINT
|
6
|
+
from geoseeq.utils import set_profile
|
6
7
|
|
7
8
|
from .copy import cli_copy
|
8
|
-
from .
|
9
|
+
from .detail import cli_detail
|
9
10
|
from .download import cli_download
|
11
|
+
from .find_grn import cli_find_grn
|
12
|
+
from .get_eula import cli_eula
|
13
|
+
from .manage import cli_manage
|
14
|
+
from .run import cli_app
|
15
|
+
from .search import cli_search
|
16
|
+
from .shared_params.opts_and_args import overwrite_option, yes_option
|
10
17
|
from .upload import cli_upload, cli_upload_advanced
|
11
18
|
from .user import cli_user
|
12
19
|
from .view import cli_view
|
13
|
-
from .search import cli_search
|
14
|
-
|
15
|
-
from geoseeq.knex import DEFAULT_ENDPOINT
|
16
|
-
from geoseeq.utils import set_profile
|
17
|
-
from .shared_params.opts_and_args import overwrite_option, yes_option
|
18
|
-
from .detail import cli_detail
|
19
|
-
from .run import cli_app
|
20
|
-
from .get_eula import cli_eula
|
21
|
-
from .find_grn import cli_find_grn
|
22
20
|
|
23
|
-
logger = logging.getLogger(
|
21
|
+
logger = logging.getLogger("geoseeq_api")
|
24
22
|
handler = logging.StreamHandler()
|
25
|
-
handler.setFormatter(logging.Formatter(
|
23
|
+
handler.setFormatter(logging.Formatter("[%(levelname)s] %(name)s :: %(message)s"))
|
26
24
|
logger.addHandler(handler)
|
27
25
|
|
28
26
|
|
29
|
-
@click.group(context_settings={
|
27
|
+
@click.group(context_settings={"show_default": True})
|
30
28
|
def main():
|
31
29
|
"""Command line interface for the GeoSeeq API.
|
32
|
-
|
30
|
+
|
33
31
|
---
|
34
32
|
|
35
33
|
Use of this tool implies acceptance of the GeoSeeq End User License Agreement.
|
@@ -37,6 +35,7 @@ def main():
|
|
37
35
|
"""
|
38
36
|
pass
|
39
37
|
|
38
|
+
|
40
39
|
main.add_command(cli_download)
|
41
40
|
main.add_command(cli_upload)
|
42
41
|
main.add_command(cli_manage)
|
@@ -46,86 +45,105 @@ main.add_command(cli_app)
|
|
46
45
|
main.add_command(cli_eula)
|
47
46
|
main.add_command(cli_find_grn)
|
48
47
|
|
48
|
+
|
49
49
|
@main.command()
|
50
50
|
def version():
|
51
51
|
"""Print the version of the Geoseeq API being used.
|
52
52
|
|
53
53
|
---
|
54
|
-
|
54
|
+
|
55
55
|
Use of this tool implies acceptance of the GeoSeeq End User License Agreement.
|
56
56
|
Run `geoseeq eula show` to view the EULA.
|
57
57
|
"""
|
58
|
-
click.echo(
|
58
|
+
click.echo("0.7.3dev0") # remember to update pyproject.toml
|
59
59
|
|
60
60
|
|
61
|
-
@main.group(
|
61
|
+
@main.group("advanced")
|
62
62
|
def cli_advanced():
|
63
63
|
"""Advanced commands."""
|
64
64
|
pass
|
65
65
|
|
66
|
+
|
66
67
|
cli_advanced.add_command(cli_copy)
|
67
68
|
cli_advanced.add_command(cli_user)
|
68
69
|
cli_advanced.add_command(cli_detail)
|
69
70
|
cli_advanced.add_command(cli_upload_advanced)
|
70
71
|
|
71
|
-
|
72
|
+
|
73
|
+
@cli_advanced.group("experimental")
|
72
74
|
def cli_experimental():
|
73
75
|
"""Experimental commands."""
|
74
76
|
pass
|
75
77
|
|
76
78
|
|
77
|
-
|
78
79
|
try:
|
79
80
|
from geoseeq.vc.cli import cli_vc
|
81
|
+
|
80
82
|
from .project import cli_project
|
83
|
+
|
81
84
|
cli_experimental.add_command(cli_vc)
|
82
85
|
cli_advanced.add_command(cli_project)
|
83
86
|
|
84
87
|
except (ModuleNotFoundError, ImportError):
|
85
88
|
pass
|
86
89
|
|
87
|
-
|
90
|
+
|
91
|
+
@main.command("config")
|
88
92
|
@yes_option
|
89
|
-
@click.option(
|
90
|
-
@click.option(
|
91
|
-
@click.option(
|
93
|
+
@click.option("--api-token", default=None, help="The API token to use.")
|
94
|
+
@click.option("--endpoint", default=None, help="The endpoint to use.")
|
95
|
+
@click.option("-p", "--profile", default=None, help="The profile name to use.")
|
92
96
|
@overwrite_option
|
93
97
|
def cli_config(yes, api_token, endpoint, profile, overwrite):
|
94
98
|
"""Configure the GeoSeeq API.
|
95
99
|
|
96
100
|
---
|
97
|
-
|
101
|
+
|
98
102
|
Use of this tool implies acceptance of the GeoSeeq End User License Agreement.
|
99
103
|
Run `geoseeq eula show` to view the EULA.
|
100
104
|
"""
|
101
105
|
if not profile and not yes:
|
102
|
-
profile = click.prompt(
|
106
|
+
profile = click.prompt(
|
107
|
+
f"Set custom profile name? (Leave blank for default)", default=""
|
108
|
+
).strip(" \"'")
|
103
109
|
if not endpoint:
|
104
110
|
endpoint = DEFAULT_ENDPOINT
|
105
111
|
if not yes:
|
106
|
-
endpoint = click.prompt(
|
112
|
+
endpoint = click.prompt(
|
113
|
+
f"Enter the URL to use for GeoSeeq (Most users can use the default)",
|
114
|
+
default=DEFAULT_ENDPOINT,
|
115
|
+
).strip(" \"'")
|
107
116
|
if not api_token:
|
108
|
-
api_token = click.prompt(
|
117
|
+
api_token = click.prompt(
|
118
|
+
f"Enter your GeoSeeq API token", hide_input=True
|
119
|
+
).strip(" \"'")
|
109
120
|
if not yes:
|
110
|
-
eula_accepted = click.confirm(
|
121
|
+
eula_accepted = click.confirm(
|
122
|
+
(
|
123
|
+
"Have you read and accepted the GeoSeeq End User License "
|
124
|
+
"Agreement? Use `geoseeq eula show` to view the EULA."
|
125
|
+
)
|
126
|
+
)
|
111
127
|
if not eula_accepted:
|
112
|
-
click.echo(
|
128
|
+
click.echo("You must accept the EULA to use the GeoSeeq API.")
|
113
129
|
return
|
114
130
|
set_profile(api_token, endpoint=endpoint, profile=profile, overwrite=overwrite)
|
115
|
-
click.echo(f
|
131
|
+
click.echo(f"Profile configured.")
|
116
132
|
|
117
133
|
|
118
|
-
@main.command(
|
134
|
+
@main.command("clear-cache")
|
119
135
|
@yes_option
|
120
136
|
def cli_clear_cache(yes):
|
121
137
|
"""Clear the local cache.
|
122
138
|
|
123
139
|
---
|
124
|
-
|
140
|
+
|
125
141
|
Use of this tool implies acceptance of the GeoSeeq End User License Agreement.
|
126
142
|
Run `geoseeq eula show` to view the EULA.
|
127
143
|
"""
|
128
|
-
from geoseeq.file_system_cache import GEOSEEQ_CACHE_DIR
|
129
144
|
import shutil
|
130
|
-
|
131
|
-
|
145
|
+
|
146
|
+
from geoseeq.file_system_cache import GEOSEEQ_CACHE_DIR
|
147
|
+
|
148
|
+
if yes or click.confirm("Are you sure you want to clear the cache?"):
|
149
|
+
shutil.rmtree(GEOSEEQ_CACHE_DIR, ignore_errors=True)
|
geoseeq/dashboard/dashboard.py
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
-
|
2
1
|
import logging
|
3
|
-
import json
|
4
2
|
from typing import Literal
|
5
|
-
|
6
|
-
from geoseeq.id_constructors import result_file_from_blob
|
3
|
+
|
7
4
|
from geoseeq import ProjectResultFile
|
5
|
+
from geoseeq.id_constructors import result_file_from_blob
|
6
|
+
from geoseeq.id_constructors.from_ids import result_file_from_id
|
7
|
+
from geoseeq.remote_object import RemoteObject
|
8
8
|
|
9
9
|
logger = logging.getLogger("geoseeq_api")
|
10
10
|
|
@@ -30,20 +30,31 @@ class Dashboard(RemoteObject):
|
|
30
30
|
blob.pop("tiles")
|
31
31
|
self.load_blob(blob, allow_overwrite=allow_overwrite)
|
32
32
|
|
33
|
-
def
|
33
|
+
def save(self):
|
34
34
|
self.save_tiles()
|
35
|
-
|
35
|
+
|
36
36
|
def save_tiles(self):
|
37
37
|
post_data = {"tiles": [tile._get_post_data() for tile in self.tiles]}
|
38
|
-
blob = self.knex.post(
|
38
|
+
blob = self.knex.post(
|
39
|
+
f"sample_groups/{self.project.uuid}/dashboard/{self.name}/tiles",
|
40
|
+
json=post_data,
|
41
|
+
json_response=False,
|
42
|
+
)
|
39
43
|
print(blob)
|
40
|
-
|
44
|
+
|
41
45
|
def _create(self):
|
42
46
|
post_data = {"name": self.name, "is_default": self.is_default}
|
43
|
-
blob = self.knex.post(
|
47
|
+
blob = self.knex.post(
|
48
|
+
f"sample_groups/{self.project.uuid}/dashboard", json=post_data
|
49
|
+
)
|
44
50
|
self.load_blob(blob)
|
45
|
-
|
46
|
-
def tile(
|
51
|
+
|
52
|
+
def tile(
|
53
|
+
self,
|
54
|
+
title,
|
55
|
+
result_file,
|
56
|
+
style: Literal["col-span-1", "col-span-2"] = "col-span-1",
|
57
|
+
):
|
47
58
|
result_file.get()
|
48
59
|
tile = DashboardTile(self.knex, self, title, result_file, style=style)
|
49
60
|
self.tiles.append(tile)
|
@@ -59,21 +70,20 @@ class Dashboard(RemoteObject):
|
|
59
70
|
return self._name
|
60
71
|
|
61
72
|
def __str__(self):
|
62
|
-
return f
|
63
|
-
|
73
|
+
return f'<Geoseeq Dashboard: {self.project.grn} "{self.name}"/>'
|
74
|
+
|
64
75
|
def __repr__(self):
|
65
76
|
return str(self)
|
66
|
-
|
77
|
+
|
67
78
|
@property
|
68
79
|
def grn(self):
|
69
|
-
return f
|
70
|
-
|
80
|
+
return f'grn:dashboard:{self.project.uuid}:"{self.name}"'
|
81
|
+
|
71
82
|
def pre_hash(self):
|
72
83
|
return "DASH" + self.project.uuid + self.name
|
73
84
|
|
74
85
|
|
75
86
|
class DashboardTile:
|
76
|
-
|
77
87
|
def __init__(self, knex, dashboard, title, result_file, style="col-span-1"):
|
78
88
|
self.knex = knex
|
79
89
|
self.dashboard = dashboard
|
@@ -82,9 +92,11 @@ class DashboardTile:
|
|
82
92
|
self.result_file = result_file
|
83
93
|
|
84
94
|
def _get_post_data(self):
|
85
|
-
out =
|
95
|
+
out = {
|
86
96
|
"field_uuid": self.result_file.uuid,
|
87
|
-
"field_type":
|
97
|
+
"field_type": (
|
98
|
+
"group" if isinstance(self.result_file, ProjectResultFile) else "sample"
|
99
|
+
),
|
88
100
|
"style": self.style,
|
89
101
|
"title": self.title,
|
90
102
|
"has_related_field": False,
|
@@ -93,11 +105,157 @@ class DashboardTile:
|
|
93
105
|
|
94
106
|
@classmethod
|
95
107
|
def from_blob(cls, dashboard, blob):
|
96
|
-
result_file = result_file_from_blob(blob["viz_field"])
|
97
|
-
return cls(
|
98
|
-
|
108
|
+
result_file = result_file_from_blob(dashboard.knex, blob["viz_field"])
|
109
|
+
return cls(
|
110
|
+
dashboard.knex, dashboard, blob["title"], result_file, style=blob["style"]
|
111
|
+
)
|
112
|
+
|
113
|
+
def __str__(self) -> str:
|
114
|
+
return f'<Geoseeq DashboardTile: {self.dashboard.grn} "{self.title}" />'
|
115
|
+
|
116
|
+
def __repr__(self) -> str:
|
117
|
+
return str(self)
|
118
|
+
|
119
|
+
|
120
|
+
class SampleDashboard(RemoteObject):
|
121
|
+
"""Dashboard client for a single sample."""
|
122
|
+
|
123
|
+
parent_field = "sample"
|
124
|
+
remote_fields = ["uuid", "title", "default", "created_at", "updated_at"]
|
125
|
+
|
126
|
+
def __init__(self, knex, sample, title="Default dashboard", default=False):
|
127
|
+
super().__init__(self)
|
128
|
+
self.knex = knex
|
129
|
+
self.sample = sample
|
130
|
+
self.title = title
|
131
|
+
self.tiles = []
|
132
|
+
self.default = default
|
133
|
+
|
134
|
+
def _get(self, allow_overwrite=False):
|
135
|
+
blob = self.knex.get(f"samples/{self.sample.uuid}/dashboards")
|
136
|
+
try:
|
137
|
+
blob = [
|
138
|
+
dashboard_blob
|
139
|
+
for dashboard_blob in blob["results"]
|
140
|
+
if dashboard_blob["title"] == self.title
|
141
|
+
][0]
|
142
|
+
except IndexError:
|
143
|
+
raise ValueError(f"There is no existing dashboard with title {self.title}")
|
144
|
+
|
145
|
+
self.load_blob(blob, allow_overwrite=allow_overwrite)
|
146
|
+
|
147
|
+
# Load tiles
|
148
|
+
tiles_res = self.knex.get(f"samples/dashboards/{self.uuid}/tiles")
|
149
|
+
for tile_blob in tiles_res["results"]:
|
150
|
+
tile = SampleDashboardTile.from_blob(self, tile_blob)
|
151
|
+
self.tiles.append(tile)
|
152
|
+
|
153
|
+
def save(self):
|
154
|
+
data = self._get_post_data()
|
155
|
+
url = f"samples/{self.sample.uuid}/dashboards/{self.uuid}"
|
156
|
+
self.knex.put(url, json=data)
|
157
|
+
self.save_tiles()
|
158
|
+
|
159
|
+
def save_tiles(self):
|
160
|
+
post_data = {"tiles": [tile._get_post_data() for tile in self.tiles]}
|
161
|
+
self.knex.put(
|
162
|
+
f"samples/dashboards/{self.uuid}/tiles",
|
163
|
+
json=post_data,
|
164
|
+
json_response=False,
|
165
|
+
)
|
166
|
+
|
167
|
+
def delete(self):
|
168
|
+
self.knex.delete(f"samples/{self.sample.uuid}/dashboards/{self.uuid}")
|
169
|
+
self._already_fetched = False
|
170
|
+
self._deleted = True
|
171
|
+
|
172
|
+
def _create(self):
|
173
|
+
post_data = {
|
174
|
+
"title": self.title,
|
175
|
+
"sample": self.sample.uuid,
|
176
|
+
"default": self.default,
|
177
|
+
}
|
178
|
+
blob = self.knex.post(f"samples/{self.sample.uuid}/dashboards", json=post_data)
|
179
|
+
self.load_blob(blob)
|
180
|
+
|
181
|
+
def _get_post_data(self):
|
182
|
+
out = {
|
183
|
+
"sample": self.sample.uuid,
|
184
|
+
"title": self.title,
|
185
|
+
"default": self.default,
|
186
|
+
}
|
187
|
+
return out
|
188
|
+
|
189
|
+
def add_tile(self, result_file, title, width="half", order=None):
|
190
|
+
result_file.get()
|
191
|
+
tile = SampleDashboardTile(
|
192
|
+
self.knex, self, title, result_file, width=width, order=order
|
193
|
+
)
|
194
|
+
self.tiles.append(tile)
|
195
|
+
self._modified = True
|
196
|
+
|
197
|
+
@classmethod
|
198
|
+
def from_blob(cls, sample, blob):
|
199
|
+
instance = cls(
|
200
|
+
sample.knex,
|
201
|
+
sample,
|
202
|
+
blob["title"],
|
203
|
+
blob["default"],
|
204
|
+
)
|
205
|
+
instance.uuid = blob["uuid"]
|
206
|
+
return instance
|
207
|
+
|
208
|
+
@property
|
209
|
+
def name(self):
|
210
|
+
return self.title
|
211
|
+
|
212
|
+
def __str__(self):
|
213
|
+
return f'<Geoseeq SampleDashboard: {self.sample.brn} "{self.name}"/>'
|
214
|
+
|
215
|
+
def __repr__(self):
|
216
|
+
return str(self)
|
217
|
+
|
218
|
+
@property
|
219
|
+
def grn(self):
|
220
|
+
return f'grn:dashboard:{self.sample.uuid}:"{self.name}"'
|
221
|
+
|
222
|
+
def pre_hash(self):
|
223
|
+
return "DASH" + self.sample.uuid + self.name
|
224
|
+
|
225
|
+
|
226
|
+
class SampleDashboardTile:
|
227
|
+
def __init__(self, knex, dashboard, title, result_file, width="half", order=None):
|
228
|
+
self.knex = knex
|
229
|
+
self.dashboard = dashboard
|
230
|
+
self.title = title
|
231
|
+
self.width = width
|
232
|
+
self.result_file = result_file
|
233
|
+
self.order = order
|
234
|
+
|
235
|
+
def _get_post_data(self):
|
236
|
+
out = {
|
237
|
+
"field": self.result_file.uuid,
|
238
|
+
"dashboard": self.dashboard.uuid,
|
239
|
+
"width": self.width,
|
240
|
+
"title": self.title,
|
241
|
+
"order": self.order,
|
242
|
+
}
|
243
|
+
return out
|
244
|
+
|
245
|
+
@classmethod
|
246
|
+
def from_blob(cls, dashboard, blob):
|
247
|
+
result_file = result_file_from_id(dashboard.knex, blob["field_obj"]["uuid"])
|
248
|
+
return cls(
|
249
|
+
dashboard.knex,
|
250
|
+
dashboard,
|
251
|
+
blob["title"],
|
252
|
+
result_file,
|
253
|
+
width=blob["width"],
|
254
|
+
order=blob["order"],
|
255
|
+
)
|
256
|
+
|
99
257
|
def __str__(self) -> str:
|
100
|
-
return f
|
101
|
-
|
258
|
+
return f'<Geoseeq DashboardTile: {self.dashboard.grn} "{self.title}" />'
|
259
|
+
|
102
260
|
def __repr__(self) -> str:
|
103
|
-
return str(self)
|
261
|
+
return str(self)
|
geoseeq/project.py
CHANGED
@@ -358,4 +358,9 @@ class Project(RemoteObject):
|
|
358
358
|
def grn(self):
|
359
359
|
return f"grn::project:{self.uuid}"
|
360
360
|
|
361
|
+
def set_description(self, description):
|
362
|
+
self.description = description
|
363
|
+
self._modified = True
|
364
|
+
return self
|
365
|
+
|
361
366
|
SampleGroup = Project # alias for backwards compatibility
|
geoseeq/sample.py
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
import urllib
|
2
|
-
|
3
2
|
from .remote_object import RemoteObject
|
4
3
|
from .result import SampleResultFile, SampleResultFolder
|
5
4
|
|
@@ -32,7 +31,7 @@ class Sample(RemoteObject):
|
|
32
31
|
|
33
32
|
@property
|
34
33
|
def brn(self):
|
35
|
-
return f
|
34
|
+
return f"brn:{self.knex.instance_code()}:sample:{self.uuid}"
|
36
35
|
|
37
36
|
def nested_url(self):
|
38
37
|
escaped_name = urllib.parse.quote(self.name, safe="")
|
@@ -63,15 +62,19 @@ class Sample(RemoteObject):
|
|
63
62
|
self.load_blob(blob, allow_overwrite=allow_overwrite)
|
64
63
|
|
65
64
|
def get_post_data(self):
|
66
|
-
data = {
|
65
|
+
data = {
|
66
|
+
field: getattr(self, field)
|
67
|
+
for field in self.remote_fields
|
68
|
+
if hasattr(self, field)
|
69
|
+
}
|
67
70
|
data["library"] = self.lib.uuid
|
68
71
|
if self.new_lib:
|
69
72
|
if isinstance(self.new_lib, RemoteObject):
|
70
73
|
data["library"] = self.new_lib.uuid
|
71
74
|
else:
|
72
75
|
data["library"] = self.new_lib
|
73
|
-
if data[
|
74
|
-
data.pop(
|
76
|
+
if data["uuid"] is None:
|
77
|
+
data.pop("uuid")
|
75
78
|
return data
|
76
79
|
|
77
80
|
def _create(self):
|
@@ -96,10 +99,10 @@ class Sample(RemoteObject):
|
|
96
99
|
|
97
100
|
def analysis_result(self, *args, **kwargs):
|
98
101
|
"""Return a SampleResultFolder for this sample.
|
99
|
-
|
102
|
+
|
100
103
|
This is an alias for result_folder."""
|
101
104
|
return self.result_folder(*args, **kwargs)
|
102
|
-
|
105
|
+
|
103
106
|
def get_result_folders(self, cache=True):
|
104
107
|
"""Yield sample analysis results fetched from the server."""
|
105
108
|
self.get()
|
@@ -107,7 +110,7 @@ class Sample(RemoteObject):
|
|
107
110
|
for ar in self._get_result_cache:
|
108
111
|
yield ar
|
109
112
|
return
|
110
|
-
url =
|
113
|
+
url = f"sample_ars?sample_id={self.uuid}"
|
111
114
|
result = self.knex.get(url)
|
112
115
|
for result_blob in result["results"]:
|
113
116
|
result = self.analysis_result(result_blob["module_name"])
|
@@ -126,7 +129,7 @@ class Sample(RemoteObject):
|
|
126
129
|
|
127
130
|
def get_analysis_results(self, cache=True):
|
128
131
|
"""Yield sample analysis results fetched from the server.
|
129
|
-
|
132
|
+
|
130
133
|
This is an alias for get_result_folders.
|
131
134
|
"""
|
132
135
|
return self.get_result_folders(cache=cache)
|
@@ -135,14 +138,15 @@ class Sample(RemoteObject):
|
|
135
138
|
"""Return a manifest for this sample."""
|
136
139
|
url = f"samples/{self.uuid}/manifest"
|
137
140
|
return self.knex.get(url)
|
138
|
-
|
141
|
+
|
139
142
|
def _grn_to_file(self, grn):
|
140
143
|
from geoseeq.id_constructors.from_blobs import sample_result_file_from_blob
|
144
|
+
|
141
145
|
file_uuid = grn.split(":")[-1]
|
142
146
|
file_blob = self.knex.get(f"sample_ar_fields/{file_uuid}")
|
143
147
|
file = sample_result_file_from_blob(self.knex, file_blob)
|
144
148
|
return file
|
145
|
-
|
149
|
+
|
146
150
|
def get_one_fastq(self):
|
147
151
|
"""Return a 2-ple, a fastq ResultFile and a string with the read type.
|
148
152
|
|
@@ -152,10 +156,10 @@ class Sample(RemoteObject):
|
|
152
156
|
blob = self.knex.get(url)
|
153
157
|
file = self._grn_to_file(blob["grn"])
|
154
158
|
return file, blob["read_type"]
|
155
|
-
|
159
|
+
|
156
160
|
def get_one_fastq_folder(self, preference_order=None):
|
157
161
|
"""Return a 3-ple, <read_type:str>, <folder_name:str>, a list with reads.
|
158
|
-
|
162
|
+
|
159
163
|
If the read type is paired end, the list will contain 2-ples with reads.
|
160
164
|
|
161
165
|
Default preference order is:
|
@@ -175,7 +179,7 @@ class Sample(RemoteObject):
|
|
175
179
|
for folder_name, reads in all_fastqs[read_type].items():
|
176
180
|
return read_type, folder_name, reads
|
177
181
|
raise ValueError("No suitable fastq found")
|
178
|
-
|
182
|
+
|
179
183
|
def get_all_fastqs(self):
|
180
184
|
"""Return a dict with the following structure:
|
181
185
|
|
@@ -217,7 +221,7 @@ class Sample(RemoteObject):
|
|
217
221
|
self._grn_to_file(file_grns[0])
|
218
222
|
)
|
219
223
|
return files
|
220
|
-
|
224
|
+
|
221
225
|
def get_one_fasta(self):
|
222
226
|
"""Return a 2-ple, a fasta ResultFile and a string with the read type.
|
223
227
|
|
@@ -228,6 +232,70 @@ class Sample(RemoteObject):
|
|
228
232
|
file = self._grn_to_file(blob["grn"])
|
229
233
|
return file, blob["read_type"]
|
230
234
|
|
235
|
+
def create_dashboard(self, title="Default dashboard", default=False):
|
236
|
+
from geoseeq.dashboard.dashboard import SampleDashboard
|
237
|
+
|
238
|
+
post_data = {
|
239
|
+
"title": title,
|
240
|
+
"sample": self.uuid,
|
241
|
+
"default": default,
|
242
|
+
}
|
243
|
+
blob = self.knex.post(f"samples/{self.uuid}/dashboards", json=post_data)
|
244
|
+
dashboard = SampleDashboard(
|
245
|
+
self.knex, self, title=blob["title"], default=blob["default"]
|
246
|
+
)
|
247
|
+
dashboard.uuid = blob["uuid"]
|
248
|
+
dashboard._already_fetched = True
|
249
|
+
return dashboard
|
250
|
+
|
251
|
+
def get_default_dashbaord(self):
|
252
|
+
from geoseeq.dashboard.dashboard import SampleDashboard
|
253
|
+
|
254
|
+
dashboard_resp = self.knex.get(f"samples/{self.uuid}/dashboards")
|
255
|
+
try:
|
256
|
+
blob = [
|
257
|
+
dashboard_blob
|
258
|
+
for dashboard_blob in dashboard_resp["results"]
|
259
|
+
if dashboard_blob["default"] == True
|
260
|
+
][0]
|
261
|
+
dashboard = SampleDashboard.from_blob(self, blob)
|
262
|
+
dashboard.get() # Tiles are not in the blob
|
263
|
+
return dashboard
|
264
|
+
except IndexError:
|
265
|
+
pass
|
266
|
+
return None
|
267
|
+
|
268
|
+
def get_or_create_default_dashbaord(self):
|
269
|
+
default_dashboard = self.get_default_dashbaord()
|
270
|
+
if default_dashboard:
|
271
|
+
return default_dashboard
|
272
|
+
else:
|
273
|
+
return self.create_dashboard(default=True)
|
274
|
+
|
275
|
+
def get_dashbaord_by_title(self, title):
|
276
|
+
from geoseeq.dashboard.dashboard import SampleDashboard
|
277
|
+
|
278
|
+
dashboard_resp = self.knex.get(f"samples/{self.uuid}/dashboards")
|
279
|
+
try:
|
280
|
+
blob = [
|
281
|
+
dashboard_blob
|
282
|
+
for dashboard_blob in dashboard_resp["results"]
|
283
|
+
if dashboard_blob["title"] == title
|
284
|
+
][0]
|
285
|
+
dashboard = SampleDashboard.from_blob(self, blob)
|
286
|
+
dashboard.get() # Tiles are not in the blob
|
287
|
+
return dashboard
|
288
|
+
except IndexError:
|
289
|
+
pass
|
290
|
+
return None
|
291
|
+
|
292
|
+
def get_or_create_dashbaord_by_title(self, title):
|
293
|
+
default_dashboard = self.get_dashbaord_by_title(title)
|
294
|
+
if default_dashboard:
|
295
|
+
return default_dashboard
|
296
|
+
else:
|
297
|
+
return self.create_dashboard(title=title)
|
298
|
+
|
231
299
|
def __str__(self):
|
232
300
|
return f"<Geoseeq::Sample {self.name} {self.uuid} />"
|
233
301
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: geoseeq
|
3
|
-
Version: 0.7.
|
3
|
+
Version: 0.7.3.dev1
|
4
4
|
Summary: GeoSeeq command line tools and python API
|
5
5
|
Project-URL: Homepage, https://github.com/biotia/geoseeq_api_client
|
6
6
|
Project-URL: Issues, https://github.com/biotia/geoseeq_api_client/issues
|
@@ -44,7 +44,7 @@ Download this directory and run `python setup.py install`
|
|
44
44
|
|
45
45
|
---
|
46
46
|
|
47
|
-
## Using the Command Line
|
47
|
+
## Using the Command Line
|
48
48
|
|
49
49
|
Run the command line by typing `geoseeq` into a terminal prompt. See available options by adding `--help`
|
50
50
|
|
@@ -60,7 +60,7 @@ Once you have a token you will need to configure GeoSeeq to use it. Run `geoseeq
|
|
60
60
|
|
61
61
|
```
|
62
62
|
$ geoseeq config
|
63
|
-
Set custom profile name? (Leave blank for default) []:
|
63
|
+
Set custom profile name? (Leave blank for default) []:
|
64
64
|
Enter the URL to use for GeoSeeq (Most users can use the default) [https://backend.geoseeq.com]:
|
65
65
|
Enter your GeoSeeq API token:
|
66
66
|
Profile configured.
|
@@ -82,11 +82,11 @@ $ geoseeq download files --extension fastq.gz "GeoSeeq/Example CLI Project"
|
|
82
82
|
|
83
83
|
#### Uploading sequencing data
|
84
84
|
|
85
|
-
GeoSeeq can automatically group fastq files into samples according to their
|
85
|
+
GeoSeeq can automatically group fastq files into samples according to their
|
86
86
|
sample name, read number, and lane number. It supports paired end, single end,
|
87
87
|
and nanopore reads.
|
88
88
|
|
89
|
-
Assume you have data from a single ended sequencing run stored as fastq files:
|
89
|
+
Assume you have data from a single ended sequencing run stored as fastq files:
|
90
90
|
- Sample1_L1_R1.fastq.gz
|
91
91
|
- Sample1_L1_R2.fastq.gz
|
92
92
|
- Sample1_L2_R1.fastq.gz
|
@@ -119,8 +119,13 @@ Note: You will need to have an API token set to use this command (see above)
|
|
119
119
|
|
120
120
|
## Using the Python API in a program
|
121
121
|
|
122
|
+
|
122
123
|
Please see `geoseeq_api/cli/download.py` for examples of how to download data using the Python API directly.
|
123
124
|
|
125
|
+
## Development in GitHub Codespaces
|
126
|
+
|
127
|
+
This repository includes a `.devcontainer` configuration so it can be opened directly in [GitHub Codespaces](https://docs.github.com/codespaces). When the codespace is created the development dependencies are installed and `pre-commit` hooks are set up automatically.
|
128
|
+
|
124
129
|
---
|
125
130
|
|
126
131
|
## Notes
|
@@ -7,9 +7,9 @@ geoseeq/file_system_cache.py,sha256=HzVZWtwLD2fjWWSo_UfWmGeBltm9He4lP_OqzKwNGWg,
|
|
7
7
|
geoseeq/knex.py,sha256=zcjafsmUn9SC3LlRnvvaXpr-pHYZ0IXk7LpzuUoE3MI,8312
|
8
8
|
geoseeq/organization.py,sha256=bJkYL8_D-k6IYAaii2ZbxjwYnXy6lvu6iLXscxKlA3w,2542
|
9
9
|
geoseeq/pipeline.py,sha256=89mhWaecsKnm6tyRkdkaVp4dmZh62_v42Ze0oXf8OTY,9873
|
10
|
-
geoseeq/project.py,sha256=
|
10
|
+
geoseeq/project.py,sha256=_8uttLKc6yVGDdJhPRmQOzzPeMYmUg0zBBPOAJc3yyo,14014
|
11
11
|
geoseeq/remote_object.py,sha256=GYN6PKU7Zz3htIdpFjfZiFejzGqqJHbJyKlefM1Eixk,7151
|
12
|
-
geoseeq/sample.py,sha256=
|
12
|
+
geoseeq/sample.py,sha256=2UmS1636bpPZbydv4PePNw-zXUs70Igt-6RTRZiCg5Q,10563
|
13
13
|
geoseeq/search.py,sha256=gawad6Cx5FxJBPlYkXWb-UKAO-UC0_yhvyU9Ca1kaNI,3388
|
14
14
|
geoseeq/smart_table.py,sha256=rihMsFUIn-vn4w6ukVZTHI9bjDSEr8xHExBfX8mwCHM,6169
|
15
15
|
geoseeq/smart_tree.py,sha256=bSjDlwmOuNXutYJhytA1RovwRCHV6ZxXXJPiIGFhPaA,1825
|
@@ -25,7 +25,7 @@ geoseeq/cli/download.py,sha256=Znjuc9IFOcIa5_Od9mFXHJdYAJtgw9Bc_wPPcOVXn7s,21298
|
|
25
25
|
geoseeq/cli/fastq_utils.py,sha256=-bmeQLaiMBm57zWOF0R5OlWTU0_3sh1JBC1RYw2BOFM,3083
|
26
26
|
geoseeq/cli/find_grn.py,sha256=oMDxkzGQBQb2_cCuvmwoeHOsFHqyO9RLeJzrB6bAe5M,439
|
27
27
|
geoseeq/cli/get_eula.py,sha256=79mbUwyiF7O1r0g6UTxG9kJGQEqKuH805E6eLkPC6Y4,997
|
28
|
-
geoseeq/cli/main.py,sha256=
|
28
|
+
geoseeq/cli/main.py,sha256=_P_pp_ohm0Pq390FgWjNw-oQA06KGbQPAGbvgY-iL6U,4137
|
29
29
|
geoseeq/cli/manage.py,sha256=wGXAcVaXqE5JQEU8Jh6OlHr02nB396bpS_SFcOZdrEo,5929
|
30
30
|
geoseeq/cli/progress_bar.py,sha256=p1Xl01nkYxSBZCB30ue2verIIi22W93m3ZAMAxipD0g,738
|
31
31
|
geoseeq/cli/project.py,sha256=V5SdXm2Hwo2lxrkpwRDedw-mAE4XnM2uwT-Gj1D90VQ,3030
|
@@ -52,7 +52,7 @@ geoseeq/contrib/ncbi/api.py,sha256=WQeLoGA_-Zha-QeSO8_i7HpvXyD8UkV0qc5okm11KiA,1
|
|
52
52
|
geoseeq/contrib/ncbi/bioproject.py,sha256=_oThTd_iLDOC8cLOlJKAatSr362OBYZCEV3YrqodhFg,4341
|
53
53
|
geoseeq/contrib/ncbi/cli.py,sha256=j9zEcaZPTryK3a4xluRxigcJKDhRpRxbp3KZSx-Bfhk,2400
|
54
54
|
geoseeq/contrib/ncbi/setup_logging.py,sha256=Tp1bY1U0f-o739aHpvVYriG2qdd1lFvCYBXZeXQgt-w,175
|
55
|
-
geoseeq/dashboard/dashboard.py,sha256=
|
55
|
+
geoseeq/dashboard/dashboard.py,sha256=nradpMc6UscnekppJaRh4od2XZ_t601UX3uWrB1StK8,7736
|
56
56
|
geoseeq/file_system/filesystem_download.py,sha256=8bcnxjWltekmCvb5N0b1guBIjLp4-CL2VtsEok-snv4,16963
|
57
57
|
geoseeq/file_system/main.py,sha256=4HgYGq7WhlF96JlVIf16iFBTDujlBpxImmtoh4VCzDA,3627
|
58
58
|
geoseeq/id_constructors/__init__.py,sha256=w5E0PNQ9UuAxBeZbDI7KBnUoERd85gGz3nScz45bd2o,126
|
@@ -92,8 +92,8 @@ geoseeq/vc/vc_cache.py,sha256=P4LXTbq2zOIv1OhP7Iw5MmypR2vXuy29Pq5K6gRvi-M,730
|
|
92
92
|
geoseeq/vc/vc_dir.py,sha256=A9CLTh2wWCRzZjiLyqXD1vhtsWZGD3OjaMT5KqlfAXI,457
|
93
93
|
geoseeq/vc/vc_sample.py,sha256=qZeioWydXvfu4rGMs20nICfNcp46y_XkND-bHdV6P5M,3850
|
94
94
|
geoseeq/vc/vc_stub.py,sha256=IQr8dI0zsWKVAeY_5ybDD6n49_3othcgfHS3P0O9tuY,3110
|
95
|
-
geoseeq-0.7.
|
96
|
-
geoseeq-0.7.
|
97
|
-
geoseeq-0.7.
|
98
|
-
geoseeq-0.7.
|
99
|
-
geoseeq-0.7.
|
95
|
+
geoseeq-0.7.3.dev1.dist-info/METADATA,sha256=7cN6ntZDU2NtQYiUAB3D12fTbm_fShr46JxHwV5qF4A,5415
|
96
|
+
geoseeq-0.7.3.dev1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
97
|
+
geoseeq-0.7.3.dev1.dist-info/entry_points.txt,sha256=yF-6KDM8zXib4Al0qn49TX-qM7PUkWUIcYtsgt36rjM,45
|
98
|
+
geoseeq-0.7.3.dev1.dist-info/licenses/LICENSE,sha256=IuhIl1XCxXLPLJT_coN1CNqQU4Khlq7x4IdW7ioOJD8,1067
|
99
|
+
geoseeq-0.7.3.dev1.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|