comparison env/lib/python3.9/site-packages/bioblend/galaxy/objects/client.py @ 0:4f3585e2f14b draft default tip

"planemo upload commit 60cee0fc7c0cda8592644e1aad72851dec82c959"
author shellac
date Mon, 22 Mar 2021 18:12:50 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:4f3585e2f14b
1 """
2 Clients for interacting with specific Galaxy entity types.
3
4 Classes in this module should not be instantiated directly, but used
5 via their handles in :class:`~.galaxy_instance.GalaxyInstance`.
6 """
7 import abc
8 import json
9 from collections.abc import (
10 Mapping,
11 Sequence,
12 )
13
14 import bioblend
15 from . import wrappers
16
17
18 class ObjClient(metaclass=abc.ABCMeta):
19
20 @abc.abstractmethod
21 def __init__(self, obj_gi):
22 self.obj_gi = obj_gi
23 self.gi = self.obj_gi.gi
24 self.log = bioblend.log
25
26 @abc.abstractmethod
27 def get_previews(self, **kwargs):
28 """
29 Get a list of object previews.
30
31 Previews entity summaries provided by REST collection URIs, e.g.
32 ``http://host:port/api/libraries``. Being the most lightweight objects
33 associated to the various entities, these are the ones that should be
34 used to retrieve their basic info.
35
36 :rtype: list
37 :return: a list of object previews
38 """
39 pass
40
41 @abc.abstractmethod
42 def list(self, **kwargs):
43 """
44 Get a list of objects.
45
46 This method first gets the entity summaries, then gets the complete
47 description for each entity with an additional GET call, so may be slow.
48
49 :rtype: list
50 :return: a list of objects
51 """
52 pass
53
54 def _select_ids(self, id_=None, name=None):
55 """
56 Return the id list that corresponds to the given id or name info.
57 """
58 if id_ is None and name is None:
59 self._error('neither id nor name provided', err_type=TypeError)
60 if id_ is not None and name is not None:
61 self._error('both id and name provided', err_type=TypeError)
62 if id_ is None:
63 return [_.id for _ in self.get_previews(name=name)]
64 else:
65 return [id_]
66
67 def _error(self, msg, err_type=RuntimeError):
68 self.log.error(msg)
69 raise err_type(msg)
70
71 def _get_dict(self, meth_name, reply):
72 if reply is None:
73 self._error('%s: no reply' % meth_name)
74 elif isinstance(reply, Mapping):
75 return reply
76 try:
77 return reply[0]
78 except (TypeError, IndexError):
79 self._error(f'{meth_name}: unexpected reply: {reply!r}')
80
81
82 class ObjDatasetContainerClient(ObjClient):
83
84 def _get_container(self, id_, ctype):
85 show_fname = 'show_%s' % ctype.__name__.lower()
86 gi_client = getattr(self.gi, ctype.API_MODULE)
87 show_f = getattr(gi_client, show_fname)
88 res = show_f(id_)
89 cdict = self._get_dict(show_fname, res)
90 cdict['id'] = id_ # overwrite unencoded id
91 c_infos = show_f(id_, contents=True)
92 if not isinstance(c_infos, Sequence):
93 self._error(f'{show_fname}: unexpected reply: {c_infos!r}')
94 c_infos = [ctype.CONTENT_INFO_TYPE(_) for _ in c_infos]
95 return ctype(cdict, content_infos=c_infos, gi=self.obj_gi)
96
97
98 class ObjLibraryClient(ObjDatasetContainerClient):
99 """
100 Interacts with Galaxy libraries.
101 """
102
103 def __init__(self, obj_gi):
104 super().__init__(obj_gi)
105
106 def create(self, name, description=None, synopsis=None):
107 """
108 Create a data library with the properties defined in the arguments.
109
110 :rtype: :class:`~.wrappers.Library`
111 :return: the library just created
112 """
113 res = self.gi.libraries.create_library(name, description, synopsis)
114 lib_info = self._get_dict('create_library', res)
115 return self.get(lib_info['id'])
116
117 def get(self, id_):
118 """
119 Retrieve the data library corresponding to the given id.
120
121 :rtype: :class:`~.wrappers.Library`
122 :return: the library corresponding to ``id_``
123 """
124 return self._get_container(id_, wrappers.Library)
125
126 def get_previews(self, name=None, deleted=False):
127 dicts = self.gi.libraries.get_libraries(name=name, deleted=deleted)
128 return [wrappers.LibraryPreview(_, gi=self.obj_gi) for _ in dicts]
129
130 def list(self, name=None, deleted=False):
131 """
132 Get libraries owned by the user of this Galaxy instance.
133
134 :type name: str
135 :param name: return only libraries with this name
136 :type deleted: bool
137 :param deleted: if ``True``, return libraries that have been deleted
138
139 :rtype: list of :class:`~.wrappers.Library`
140 """
141 dicts = self.gi.libraries.get_libraries(name=name, deleted=deleted)
142 if not deleted:
143 # return Library objects only for not-deleted libraries since Galaxy
144 # does not filter them out and Galaxy release_14.08 and earlier
145 # crashes when trying to get a deleted library
146 return [self.get(_['id']) for _ in dicts if not _['deleted']]
147 else:
148 return [self.get(_['id']) for _ in dicts]
149
150 def delete(self, id_=None, name=None):
151 """
152 Delete the library with the given id or name.
153
154 Note that the same name can map to multiple libraries.
155
156 .. warning::
157 Deleting a data library is irreversible - all of the data from
158 the library will be permanently deleted.
159 """
160 for id_ in self._select_ids(id_=id_, name=name):
161 res = self.gi.libraries.delete_library(id_)
162 if not isinstance(res, Mapping):
163 self._error(f'delete_library: unexpected reply: {res!r}')
164
165
166 class ObjHistoryClient(ObjDatasetContainerClient):
167 """
168 Interacts with Galaxy histories.
169 """
170
171 def __init__(self, obj_gi):
172 super().__init__(obj_gi)
173
174 def create(self, name=None):
175 """
176 Create a new Galaxy history, optionally setting its name.
177
178 :rtype: :class:`~.wrappers.History`
179 :return: the history just created
180 """
181 res = self.gi.histories.create_history(name=name)
182 hist_info = self._get_dict('create_history', res)
183 return self.get(hist_info['id'])
184
185 def get(self, id_):
186 """
187 Retrieve the history corresponding to the given id.
188
189 :rtype: :class:`~.wrappers.History`
190 :return: the history corresponding to ``id_``
191 """
192 return self._get_container(id_, wrappers.History)
193
194 def get_previews(self, name=None, deleted=False):
195 dicts = self.gi.histories.get_histories(name=name, deleted=deleted)
196 return [wrappers.HistoryPreview(_, gi=self.obj_gi) for _ in dicts]
197
198 def list(self, name=None, deleted=False):
199 """
200 Get histories owned by the user of this Galaxy instance.
201
202 :type name: str
203 :param name: return only histories with this name
204 :type deleted: bool
205 :param deleted: if ``True``, return histories that have been deleted
206
207 :rtype: list of :class:`~.wrappers.History`
208 """
209 dicts = self.gi.histories.get_histories(name=name, deleted=deleted)
210 return [self.get(_['id']) for _ in dicts]
211
212 def delete(self, id_=None, name=None, purge=False):
213 """
214 Delete the history with the given id or name.
215
216 Note that the same name can map to multiple histories.
217
218 :type purge: bool
219 :param purge: if ``True``, also purge (permanently delete) the history
220
221 .. note::
222 For the purge option to work, the Galaxy instance must have the
223 ``allow_user_dataset_purge`` option set to ``true`` in the
224 ``config/galaxy.yml`` configuration file.
225 """
226 for id_ in self._select_ids(id_=id_, name=name):
227 res = self.gi.histories.delete_history(id_, purge=purge)
228 if not isinstance(res, Mapping):
229 self._error(f'delete_history: unexpected reply: {res!r}')
230
231
232 class ObjWorkflowClient(ObjClient):
233 """
234 Interacts with Galaxy workflows.
235 """
236
237 def __init__(self, obj_gi):
238 super().__init__(obj_gi)
239
240 def import_new(self, src, publish=False):
241 """
242 Imports a new workflow into Galaxy.
243
244 :type src: dict or str
245 :param src: deserialized (dictionary) or serialized (str) JSON
246 dump of the workflow (this is normally obtained by exporting
247 a workflow from Galaxy).
248
249 :type publish: bool
250 :param publish: if ``True`` the uploaded workflow will be published;
251 otherwise it will be visible only by the user which uploads it (default).
252
253 :rtype: :class:`~.wrappers.Workflow`
254 :return: the workflow just imported
255 """
256 if isinstance(src, Mapping):
257 wf_dict = src
258 else:
259 try:
260 wf_dict = json.loads(src)
261 except (TypeError, ValueError):
262 self._error(f'src not supported: {src!r}')
263 wf_info = self.gi.workflows.import_workflow_dict(wf_dict, publish)
264 return self.get(wf_info['id'])
265
266 def import_shared(self, id_):
267 """
268 Imports a shared workflow to the user's space.
269
270 :type id_: str
271 :param id_: workflow id
272
273 :rtype: :class:`~.wrappers.Workflow`
274 :return: the workflow just imported
275 """
276 wf_info = self.gi.workflows.import_shared_workflow(id_)
277 return self.get(wf_info['id'])
278
279 def get(self, id_):
280 """
281 Retrieve the workflow corresponding to the given id.
282
283 :rtype: :class:`~.wrappers.Workflow`
284 :return: the workflow corresponding to ``id_``
285 """
286 res = self.gi.workflows.show_workflow(id_)
287 wf_dict = self._get_dict('show_workflow', res)
288 return wrappers.Workflow(wf_dict, gi=self.obj_gi)
289
290 # the 'deleted' option is not available for workflows
291 def get_previews(self, name=None, published=False):
292 dicts = self.gi.workflows.get_workflows(name=name, published=published)
293 return [wrappers.WorkflowPreview(_, gi=self.obj_gi) for _ in dicts]
294
295 # the 'deleted' option is not available for workflows
296 def list(self, name=None, published=False):
297 """
298 Get workflows owned by the user of this Galaxy instance.
299
300 :type name: str
301 :param name: return only workflows with this name
302 :type published: bool
303 :param published: if ``True``, return also published workflows
304
305 :rtype: list of :class:`~.wrappers.Workflow`
306 """
307 dicts = self.gi.workflows.get_workflows(name=name, published=published)
308 return [self.get(_['id']) for _ in dicts]
309
310 def delete(self, id_=None, name=None):
311 """
312 Delete the workflow with the given id or name.
313
314 Note that the same name can map to multiple workflows.
315
316 .. warning::
317 Deleting a workflow is irreversible - all of the data from
318 the workflow will be permanently deleted.
319 """
320 for id_ in self._select_ids(id_=id_, name=name):
321 res = self.gi.workflows.delete_workflow(id_)
322 if not isinstance(res, str):
323 self._error('delete_workflow: unexpected reply: %r' % res)
324
325
326 class ObjToolClient(ObjClient):
327 """
328 Interacts with Galaxy tools.
329 """
330
331 def __init__(self, obj_gi):
332 super().__init__(obj_gi)
333
334 def get(self, id_, io_details=False, link_details=False):
335 """
336 Retrieve the tool corresponding to the given id.
337
338 :type io_details: bool
339 :param io_details: if True, get also input and output details
340
341 :type link_details: bool
342 :param link_details: if True, get also link details
343
344 :rtype: :class:`~.wrappers.Tool`
345 :return: the tool corresponding to ``id_``
346 """
347 res = self.gi.tools.show_tool(id_, io_details=io_details,
348 link_details=link_details)
349 tool_dict = self._get_dict('show_tool', res)
350 return wrappers.Tool(tool_dict, gi=self.obj_gi)
351
352 def get_previews(self, name=None, trackster=None):
353 """
354 Get the list of tools installed on the Galaxy instance.
355
356 :type name: str
357 :param name: return only tools with this name
358
359 :type trackster: bool
360 :param trackster: if True, only tools that are compatible with
361 Trackster are returned
362
363 :rtype: list of :class:`~.wrappers.Tool`
364 """
365 dicts = self.gi.tools.get_tools(name=name, trackster=trackster)
366 return [wrappers.Tool(_, gi=self.obj_gi) for _ in dicts]
367
368 # the 'deleted' option is not available for tools
369 def list(self, name=None, trackster=None):
370 """
371 Get the list of tools installed on the Galaxy instance.
372
373 :type name: str
374 :param name: return only tools with this name
375
376 :type trackster: bool
377 :param trackster: if True, only tools that are compatible with
378 Trackster are returned
379
380 :rtype: list of :class:`~.wrappers.Tool`
381 """
382 # dicts = self.gi.tools.get_tools(name=name, trackster=trackster)
383 # return [self.get(_['id']) for _ in dicts]
384 # As of 2015/04/15, GET /api/tools returns also data manager tools for
385 # non-admin users, see
386 # https://trello.com/c/jyl0cvFP/2633-api-tool-list-filtering-doesn-t-filter-data-managers-for-non-admins
387 # Trying to get() a data manager tool would then return a 404 Not Found
388 # error.
389 # Moreover, the dicts returned by gi.tools.get_tools() are richer than
390 # those returned by get(), so make this an alias for get_previews().
391 return self.get_previews(name, trackster)
392
393
394 class ObjJobClient(ObjClient):
395 """
396 Interacts with Galaxy jobs.
397 """
398
399 def __init__(self, obj_gi):
400 super().__init__(obj_gi)
401
402 def get(self, id_, full_details=False):
403 """
404 Retrieve the job corresponding to the given id.
405
406 :type full_details: bool
407 :param full_details: if ``True``, return the complete list of details
408 for the given job.
409
410 :rtype: :class:`~.wrappers.Job`
411 :return: the job corresponding to ``id_``
412 """
413 res = self.gi.jobs.show_job(id_, full_details)
414 job_dict = self._get_dict('job_tool', res)
415 return wrappers.Job(job_dict, gi=self.obj_gi)
416
417 def get_previews(self):
418 dicts = self.gi.jobs.get_jobs()
419 return [wrappers.JobPreview(_, gi=self.obj_gi) for _ in dicts]
420
421 def list(self):
422 """
423 Get the list of jobs of the current user.
424
425 :rtype: list of :class:`~.wrappers.Job`
426 """
427 dicts = self.gi.jobs.get_jobs()
428 return [self.get(_['id']) for _ in dicts]