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 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 .manage import cli_manage
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('geoseeq_api')
21
+ logger = logging.getLogger("geoseeq_api")
24
22
  handler = logging.StreamHandler()
25
- handler.setFormatter(logging.Formatter('[%(levelname)s] %(name)s :: %(message)s'))
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={'show_default': True})
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('0.7.2') # remember to update pyproject.toml
58
+ click.echo("0.7.3dev0") # remember to update pyproject.toml
59
59
 
60
60
 
61
- @main.group('advanced')
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
- @cli_advanced.group('experimental')
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
- @main.command('config')
90
+
91
+ @main.command("config")
88
92
  @yes_option
89
- @click.option('--api-token', default=None, help='The API token to use.')
90
- @click.option('--endpoint', default=None, help='The endpoint to use.')
91
- @click.option('-p', '--profile', default=None, help='The profile name to use.')
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(f'Set custom profile name? (Leave blank for default)', default="").strip(' \"\'')
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(f'Enter the URL to use for GeoSeeq (Most users can use the default)', default=DEFAULT_ENDPOINT).strip(' \"\'')
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(f'Enter your GeoSeeq API token', hide_input=True).strip(' \"\'')
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(f'Have you read and accepted the GeoSeeq End User License Agreement? Use `geoseeq eula show` to view the EULA.')
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('You must accept the EULA to use the GeoSeeq API.')
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'Profile configured.')
131
+ click.echo(f"Profile configured.")
116
132
 
117
133
 
118
- @main.command('clear-cache')
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
- if yes or click.confirm('Are you sure you want to clear the cache?'):
131
- shutil.rmtree(GEOSEEQ_CACHE_DIR, ignore_errors=True)
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)
@@ -1,10 +1,10 @@
1
-
2
1
  import logging
3
- import json
4
2
  from typing import Literal
5
- from geoseeq.remote_object import RemoteObject
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 _save(self):
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(f"sample_groups/{self.project.uuid}/dashboard/{self.name}/tiles", json=post_data, json_response=False)
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(f"sample_groups/{self.project.uuid}/dashboard", json=post_data)
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(self, title, result_file, style: Literal["col-span-1", "col-span-2"]="col-span-1"):
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"<Geoseeq Dashboard: {self.project.grn} \"{self.name}\"/>"
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"grn:dashboard:{self.project.uuid}:\"{self.name}\""
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": "group" if isinstance(self.result_file, ProjectResultFile) else "sample",
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(dashboard.knex, dashboard, blob["title"], result_file, style=blob["style"])
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"<Geoseeq DashboardTile: {self.dashboard.grn} \"{self.title}\" />"
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'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.2
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=Ba3yvrSyPVnEM5_VGSQu6YPH3CTwE3fHs4JjAepEK7g,13880
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
@@ -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=uGCf-uREHdrDzQZDiBLFt6KcKcyDRHnN6vHZRSwZaYU,3982
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=HOUJoQcFGLc3JL5UVIYETq6CkQEMP2I4WaPr2u9YV3Q,3297
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.2.dist-info/METADATA,sha256=nBGfEYFfG9yWP6LWxczthpgwC5vZ5f7xi7VyaxVmz4Y,5107
96
- geoseeq-0.7.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
97
- geoseeq-0.7.2.dist-info/entry_points.txt,sha256=yF-6KDM8zXib4Al0qn49TX-qM7PUkWUIcYtsgt36rjM,45
98
- geoseeq-0.7.2.dist-info/licenses/LICENSE,sha256=IuhIl1XCxXLPLJT_coN1CNqQU4Khlq7x4IdW7ioOJD8,1067
99
- geoseeq-0.7.2.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,,