geoseeq 0.7.3.dev0__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.
@@ -3,6 +3,7 @@ from typing import Literal
3
3
 
4
4
  from geoseeq import ProjectResultFile
5
5
  from geoseeq.id_constructors import result_file_from_blob
6
+ from geoseeq.id_constructors.from_ids import result_file_from_id
6
7
  from geoseeq.remote_object import RemoteObject
7
8
 
8
9
  logger = logging.getLogger("geoseeq_api")
@@ -29,7 +30,7 @@ class Dashboard(RemoteObject):
29
30
  blob.pop("tiles")
30
31
  self.load_blob(blob, allow_overwrite=allow_overwrite)
31
32
 
32
- def _save(self):
33
+ def save(self):
33
34
  self.save_tiles()
34
35
 
35
36
  def save_tiles(self):
@@ -82,64 +83,131 @@ class Dashboard(RemoteObject):
82
83
  return "DASH" + self.project.uuid + self.name
83
84
 
84
85
 
86
+ class DashboardTile:
87
+ def __init__(self, knex, dashboard, title, result_file, style="col-span-1"):
88
+ self.knex = knex
89
+ self.dashboard = dashboard
90
+ self.title = title
91
+ self.style = style
92
+ self.result_file = result_file
93
+
94
+ def _get_post_data(self):
95
+ out = {
96
+ "field_uuid": self.result_file.uuid,
97
+ "field_type": (
98
+ "group" if isinstance(self.result_file, ProjectResultFile) else "sample"
99
+ ),
100
+ "style": self.style,
101
+ "title": self.title,
102
+ "has_related_field": False,
103
+ }
104
+ return out
105
+
106
+ @classmethod
107
+ def from_blob(cls, dashboard, blob):
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
+
85
120
  class SampleDashboard(RemoteObject):
86
121
  """Dashboard client for a single sample."""
87
122
 
88
123
  parent_field = "sample"
89
- remote_fields = ["is_default"]
124
+ remote_fields = ["uuid", "title", "default", "created_at", "updated_at"]
90
125
 
91
- def __init__(self, knex, sample, name="Default dashboard", is_default=False):
126
+ def __init__(self, knex, sample, title="Default dashboard", default=False):
92
127
  super().__init__(self)
93
128
  self.knex = knex
94
129
  self.sample = sample
95
- self._name = name
130
+ self.title = title
96
131
  self.tiles = []
97
- self.is_default = is_default
132
+ self.default = default
98
133
 
99
134
  def _get(self, allow_overwrite=False):
100
- blob = self.knex.get(f"samples/{self.sample.uuid}/dashboard-list")
101
- blob = blob["dashboard_data"][self.name]
102
- for tile_blob in blob["tiles"]:
103
- tile = DashboardTile.from_blob(self, tile_blob)
104
- self.tiles.append(tile)
105
- blob.pop("tiles")
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
+
106
145
  self.load_blob(blob, allow_overwrite=allow_overwrite)
107
146
 
108
- def _save(self):
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)
109
157
  self.save_tiles()
110
158
 
111
159
  def save_tiles(self):
112
160
  post_data = {"tiles": [tile._get_post_data() for tile in self.tiles]}
113
- self.knex.post(
114
- f"samples/{self.sample.uuid}/dashboard/{self.name}/tiles",
161
+ self.knex.put(
162
+ f"samples/dashboards/{self.uuid}/tiles",
115
163
  json=post_data,
116
164
  json_response=False,
117
165
  )
118
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
+
119
172
  def _create(self):
120
- post_data = {"name": self.name, "is_default": self.is_default}
121
- blob = self.knex.post(f"samples/{self.sample.uuid}/dashboard", json=post_data)
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)
122
179
  self.load_blob(blob)
123
180
 
124
- def tile(
125
- self,
126
- title,
127
- result_file,
128
- style: Literal["col-span-1", "col-span-2"] = "col-span-1",
129
- ):
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):
130
190
  result_file.get()
131
- tile = DashboardTile(self.knex, self, title, result_file, style=style)
191
+ tile = SampleDashboardTile(
192
+ self.knex, self, title, result_file, width=width, order=order
193
+ )
132
194
  self.tiles.append(tile)
133
195
  self._modified = True
134
- return tile
135
196
 
136
- def add_tile(self, tile):
137
- self.tiles.append(tile)
138
- self._modified = True
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
139
207
 
140
208
  @property
141
209
  def name(self):
142
- return self._name
210
+ return self.title
143
211
 
144
212
  def __str__(self):
145
213
  return f'<Geoseeq SampleDashboard: {self.sample.brn} "{self.name}"/>'
@@ -155,32 +223,35 @@ class SampleDashboard(RemoteObject):
155
223
  return "DASH" + self.sample.uuid + self.name
156
224
 
157
225
 
158
- class DashboardTile:
159
-
160
- def __init__(self, knex, dashboard, title, result_file, style="col-span-1"):
226
+ class SampleDashboardTile:
227
+ def __init__(self, knex, dashboard, title, result_file, width="half", order=None):
161
228
  self.knex = knex
162
229
  self.dashboard = dashboard
163
230
  self.title = title
164
- self.style = style
231
+ self.width = width
165
232
  self.result_file = result_file
233
+ self.order = order
166
234
 
167
235
  def _get_post_data(self):
168
236
  out = {
169
- "field_uuid": self.result_file.uuid,
170
- "field_type": (
171
- "group" if isinstance(self.result_file, ProjectResultFile) else "sample"
172
- ),
173
- "style": self.style,
237
+ "field": self.result_file.uuid,
238
+ "dashboard": self.dashboard.uuid,
239
+ "width": self.width,
174
240
  "title": self.title,
175
- "has_related_field": False,
241
+ "order": self.order,
176
242
  }
177
243
  return out
178
244
 
179
245
  @classmethod
180
246
  def from_blob(cls, dashboard, blob):
181
- result_file = result_file_from_blob(dashboard.knex, blob["viz_field"])
247
+ result_file = result_file_from_id(dashboard.knex, blob["field_obj"]["uuid"])
182
248
  return cls(
183
- dashboard.knex, dashboard, blob["title"], result_file, style=blob["style"]
249
+ dashboard.knex,
250
+ dashboard,
251
+ blob["title"],
252
+ result_file,
253
+ width=blob["width"],
254
+ order=blob["order"],
184
255
  )
185
256
 
186
257
  def __str__(self) -> str:
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'brn:{self.knex.instance_code()}:sample:{self.uuid}'
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 = {field: getattr(self, field) for field in self.remote_fields if hasattr(self, field)}
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['uuid'] is None:
74
- data.pop('uuid')
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 = f"sample_ars?sample_id={self.uuid}"
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.dev0
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
@@ -9,7 +9,7 @@ geoseeq/organization.py,sha256=bJkYL8_D-k6IYAaii2ZbxjwYnXy6lvu6iLXscxKlA3w,2542
9
9
  geoseeq/pipeline.py,sha256=89mhWaecsKnm6tyRkdkaVp4dmZh62_v42Ze0oXf8OTY,9873
10
10
  geoseeq/project.py,sha256=_8uttLKc6yVGDdJhPRmQOzzPeMYmUg0zBBPOAJc3yyo,14014
11
11
  geoseeq/remote_object.py,sha256=GYN6PKU7Zz3htIdpFjfZiFejzGqqJHbJyKlefM1Eixk,7151
12
- geoseeq/sample.py,sha256=HAfMiDPHp1UJgIA2lI6oGnNit4YKyj7nx9X07CCN98U,8316
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
@@ -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=0ISzcTby35oJVsOCeg4b_7Em6hRsh3QzsnbChf946Eo,5564
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.3.dev0.dist-info/METADATA,sha256=GqNnxtN09jNv5HRMkxGp5D8ZfrJUyJdxlzL5-6N2Ogw,5415
96
- geoseeq-0.7.3.dev0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
97
- geoseeq-0.7.3.dev0.dist-info/entry_points.txt,sha256=yF-6KDM8zXib4Al0qn49TX-qM7PUkWUIcYtsgt36rjM,45
98
- geoseeq-0.7.3.dev0.dist-info/licenses/LICENSE,sha256=IuhIl1XCxXLPLJT_coN1CNqQU4Khlq7x4IdW7ioOJD8,1067
99
- geoseeq-0.7.3.dev0.dist-info/RECORD,,
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,,