firecloud-api-cds 0.2.0__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.
- firecloud_api_cds/__init__.py +11 -0
- firecloud_api_cds/api.py +1774 -0
- firecloud_api_cds/config.py +26 -0
- firecloud_api_cds/entity.py +71 -0
- firecloud_api_cds/errors.py +16 -0
- firecloud_api_cds/fccore.py +221 -0
- firecloud_api_cds/fiss.py +2983 -0
- firecloud_api_cds/method.py +85 -0
- firecloud_api_cds/submission.py +31 -0
- firecloud_api_cds/supervisor.py +289 -0
- firecloud_api_cds/workspace.py +323 -0
- firecloud_api_cds-0.2.0.dist-info/METADATA +18 -0
- firecloud_api_cds-0.2.0.dist-info/RECORD +15 -0
- firecloud_api_cds-0.2.0.dist-info/WHEEL +4 -0
- firecloud_api_cds-0.2.0.dist-info/licenses/LICENSE +30 -0
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
3
|
+
import api as fapi
|
|
4
|
+
from .entity import Entity
|
|
5
|
+
|
|
6
|
+
class Workspace(object):
|
|
7
|
+
"""A FireCloud Workspace.
|
|
8
|
+
|
|
9
|
+
Attributes:
|
|
10
|
+
api_url (str): API root used to interact with FireCloud,
|
|
11
|
+
normally https://api.firecloud.org/api
|
|
12
|
+
namespace (str): Google project for this workspace
|
|
13
|
+
name (str): Workspace name
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def __init__(self, namespace, name, api_url=fapi.PROD_API_ROOT):
|
|
17
|
+
"""Get an existing workspace from firecloud_api_cds by name.
|
|
18
|
+
|
|
19
|
+
This method assumes that a workspace with the given name and
|
|
20
|
+
namespace is present at the api_url given, and raises an error
|
|
21
|
+
if it does not exist. To create a new workspace, use
|
|
22
|
+
Workspace.new()
|
|
23
|
+
|
|
24
|
+
Raises:
|
|
25
|
+
FireCloudServerError: Workspace does not exist, or
|
|
26
|
+
API call fails
|
|
27
|
+
"""
|
|
28
|
+
self.api_url = api_url
|
|
29
|
+
self.namespace = namespace
|
|
30
|
+
self.name = name
|
|
31
|
+
|
|
32
|
+
## Call out to FireCloud
|
|
33
|
+
r = fapi.get_workspace(namespace, name, api_url)
|
|
34
|
+
|
|
35
|
+
fapi._check_response_code(r, 200)
|
|
36
|
+
self.data = r.json()
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@staticmethod
|
|
40
|
+
def new(namespace, name, protected=False,
|
|
41
|
+
attributes=dict(), api_url=fapi.PROD_API_ROOT):
|
|
42
|
+
"""Create a new FireCloud workspace.
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
Workspace: A new FireCloud workspace
|
|
46
|
+
|
|
47
|
+
Raises:
|
|
48
|
+
FireCloudServerError: API call failed.
|
|
49
|
+
"""
|
|
50
|
+
r = fapi.create_workspace(namespace, name, protected, attributes, api_url)
|
|
51
|
+
fapi._check_response_code(r, 201)
|
|
52
|
+
return Workspace(namespace, name, api_url)
|
|
53
|
+
|
|
54
|
+
def refresh(self):
|
|
55
|
+
"""Reload workspace metadata from firecloud_api_cds.
|
|
56
|
+
|
|
57
|
+
Workspace metadata is cached in the data attribute of a Workspace,
|
|
58
|
+
and may become stale, requiring a refresh().
|
|
59
|
+
"""
|
|
60
|
+
r = fapi.get_workspace(self.namespace, self.name, self.api_url)
|
|
61
|
+
fapi._check_response_code(r, 200)
|
|
62
|
+
self.data = r.json()
|
|
63
|
+
return self
|
|
64
|
+
|
|
65
|
+
def delete(self):
|
|
66
|
+
"""Delete the workspace from firecloud_api_cds.
|
|
67
|
+
|
|
68
|
+
Note:
|
|
69
|
+
This action cannot be undone. Be careful!
|
|
70
|
+
"""
|
|
71
|
+
r = fapi.delete_workspace(self.namespace, self.name)
|
|
72
|
+
fapi._check_response_code(r, 202)
|
|
73
|
+
|
|
74
|
+
# Getting useful information out of the bucket
|
|
75
|
+
def __str__(self):
|
|
76
|
+
"""Return a JSON representation of the bucket."""
|
|
77
|
+
return json.dumps(self.data, indent=2)
|
|
78
|
+
|
|
79
|
+
def bucket(self):
|
|
80
|
+
"""Return google bucket id for this workspace."""
|
|
81
|
+
return str(self.data["workspace"]["bucketName"])
|
|
82
|
+
|
|
83
|
+
def lock(self):
|
|
84
|
+
"""Lock this Workspace.
|
|
85
|
+
|
|
86
|
+
This causes the workspace to behave in a read-only way,
|
|
87
|
+
regardless of access permissions.
|
|
88
|
+
"""
|
|
89
|
+
r = fapi.lock_workspace(self.namespace, self.name, self.api_url)
|
|
90
|
+
fapi._check_response_code(r, 204)
|
|
91
|
+
self.data['workspace']['isLocked'] = True
|
|
92
|
+
return self
|
|
93
|
+
|
|
94
|
+
def unlock(self):
|
|
95
|
+
"""Unlock this Workspace."""
|
|
96
|
+
r = fapi.unlock_workspace(self.namespace, self.name, self.api_url)
|
|
97
|
+
fapi._check_response_code(r, 204)
|
|
98
|
+
self.data['workspace']['isLocked'] = False
|
|
99
|
+
return self
|
|
100
|
+
|
|
101
|
+
def attributes(self):
|
|
102
|
+
"""Return a dictionary of workspace attributes"""
|
|
103
|
+
return self.data["workspace"]["attributes"]
|
|
104
|
+
|
|
105
|
+
def get_attribute(self, attr):
|
|
106
|
+
"""Return value of workspace attribute.
|
|
107
|
+
|
|
108
|
+
If the attribute does not exist, return None
|
|
109
|
+
"""
|
|
110
|
+
return self.data["workspace"]["attributes"].get(attr, None)
|
|
111
|
+
|
|
112
|
+
def update_attribute(self, attr, value):
|
|
113
|
+
"""Set the value of a workspace attribute."""
|
|
114
|
+
update = [fapi._attr_up(attr, value)]
|
|
115
|
+
r = fapi.update_workspace_attributes(self.namespace, self.name,
|
|
116
|
+
update, self.api_url)
|
|
117
|
+
fapi._check_response_code(r, 200)
|
|
118
|
+
|
|
119
|
+
def remove_attribute(self, attr):
|
|
120
|
+
"""Remove attribute from a workspace.
|
|
121
|
+
|
|
122
|
+
Args:
|
|
123
|
+
attr (str): attribute name
|
|
124
|
+
"""
|
|
125
|
+
update = [fapi._attr_rem(attr)]
|
|
126
|
+
r = fapi.update_workspace_attributes(self.namespace, self.name,
|
|
127
|
+
update, self.api_url)
|
|
128
|
+
self.data["workspace"]["attributes"].pop(attr, None)
|
|
129
|
+
fapi._check_response_code(r, 200)
|
|
130
|
+
|
|
131
|
+
def import_tsv(self, tsv_file):
|
|
132
|
+
"""Upload entity data to workspace from tsv loadfile.
|
|
133
|
+
|
|
134
|
+
Args:
|
|
135
|
+
tsv_file (file): Tab-delimited file of entity data
|
|
136
|
+
"""
|
|
137
|
+
r = fapi.upload_entities_tsv(self.namespace, self.name,
|
|
138
|
+
self.tsv_file, self.api_url)
|
|
139
|
+
fapi._check_response_code(r, 201)
|
|
140
|
+
|
|
141
|
+
def get_entity(self, etype, entity_id):
|
|
142
|
+
"""Return entity in this workspace.
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
etype (str): Entity type
|
|
146
|
+
entity_id (str): Entity name/unique id
|
|
147
|
+
"""
|
|
148
|
+
r = fapi.get_entity(self.namespace, self.name, etype,
|
|
149
|
+
entity_id, self.api_url)
|
|
150
|
+
fapi._check_response_code(r, 200)
|
|
151
|
+
dresp = r.json()
|
|
152
|
+
return Entity(etype, entity_id, dresp['attributes'])
|
|
153
|
+
|
|
154
|
+
def delete_entity(self, etype, entity_id):
|
|
155
|
+
"""Delete an entity in this workspace.
|
|
156
|
+
|
|
157
|
+
Args:
|
|
158
|
+
etype (str): Entity type
|
|
159
|
+
entity_id (str): Entity name/unique id
|
|
160
|
+
"""
|
|
161
|
+
r = fapi.delete_entity(self.namespace, self.name, etype,
|
|
162
|
+
entity_id, self.api_url)
|
|
163
|
+
fapi._check_response_code(r, 202)
|
|
164
|
+
|
|
165
|
+
def import_entities(self, entities):
|
|
166
|
+
"""Upload entity objects.
|
|
167
|
+
|
|
168
|
+
Args:
|
|
169
|
+
entities: iterable of firecloud.Entity objects.
|
|
170
|
+
"""
|
|
171
|
+
edata = Entity.create_payload(entities)
|
|
172
|
+
r = fapi.upload_entities(self.namespace, self.name,
|
|
173
|
+
edata, self.api_url)
|
|
174
|
+
fapi._check_response_code(r, 201)
|
|
175
|
+
|
|
176
|
+
def create_set(self, set_id, etype, entities):
|
|
177
|
+
"""Create a set of entities and upload to FireCloud.
|
|
178
|
+
|
|
179
|
+
Args
|
|
180
|
+
etype (str): one of {"sample, "pair", "participant"}
|
|
181
|
+
entities: iterable of firecloud.Entity objects.
|
|
182
|
+
"""
|
|
183
|
+
if etype not in {"sample", "pair", "participant"}:
|
|
184
|
+
raise ValueError("Unsupported entity type:" + str(etype))
|
|
185
|
+
|
|
186
|
+
payload = "membership:" + etype + "_set_id\t" + etype + "_id\n"
|
|
187
|
+
|
|
188
|
+
for e in entities:
|
|
189
|
+
if e.etype != etype:
|
|
190
|
+
msg = "Entity type '" + e.etype + "' does not match "
|
|
191
|
+
msg += "set type '" + etype + "'"
|
|
192
|
+
raise ValueError(msg)
|
|
193
|
+
payload += set_id + '\t' + e.entity_id + '\n'
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
r = fapi.upload_entities(self.namespace, self.name,
|
|
197
|
+
payload, self.api_url)
|
|
198
|
+
fapi._check_response_code(r, 201)
|
|
199
|
+
|
|
200
|
+
def create_sample_set(self, sset_id, samples):
|
|
201
|
+
"""Create FireCloud sample_set"""
|
|
202
|
+
return self.create_set(sset_id, "sample", samples)
|
|
203
|
+
|
|
204
|
+
def create_pair_set(self, pset_id, pairs):
|
|
205
|
+
"""Create FireCloud pair_set"""
|
|
206
|
+
return self.create_set(pset_id, "pair", pairs)
|
|
207
|
+
|
|
208
|
+
def create_participant_set(self, pset_id, participants):
|
|
209
|
+
"""Create FireCloud participant_set"""
|
|
210
|
+
return self.create_set(pset_id, "participant", participants)
|
|
211
|
+
|
|
212
|
+
def submissions(self):
|
|
213
|
+
"""List job submissions in workspace."""
|
|
214
|
+
r = fapi.get_submissions(self.namespace, self.name, self.api_url)
|
|
215
|
+
fapi._check_response_code(r, 200)
|
|
216
|
+
return r.json()
|
|
217
|
+
|
|
218
|
+
def entity_types(self):
|
|
219
|
+
"""List entity types in workspace."""
|
|
220
|
+
r = fapi.get_entity_types(self.namespace, self.name, self.api_url)
|
|
221
|
+
fapi._check_response_code(r, 200)
|
|
222
|
+
return r.json().keys()
|
|
223
|
+
|
|
224
|
+
def entities(self):
|
|
225
|
+
"""List all entities in workspace."""
|
|
226
|
+
r = fapi.get_entities_with_type(self.namespace,
|
|
227
|
+
self.name, self.api_url)
|
|
228
|
+
fapi._check_response_code(r, 200)
|
|
229
|
+
edicts = r.json()
|
|
230
|
+
return [Entity(e['entityType'], e['name'], e['attributes'])
|
|
231
|
+
for e in edicts]
|
|
232
|
+
|
|
233
|
+
def __get_entities(self, etype):
|
|
234
|
+
"""Helper to get entities for a given type."""
|
|
235
|
+
r = fapi.get_entities(self.namespace, self.name,
|
|
236
|
+
etype, self.api_url)
|
|
237
|
+
fapi._check_response_code(r, 200)
|
|
238
|
+
return [Entity(e['entityType'], e['name'], e['attributes'])
|
|
239
|
+
for e in r.json()]
|
|
240
|
+
|
|
241
|
+
def samples(self):
|
|
242
|
+
"""List samples in a workspace."""
|
|
243
|
+
return self.__get_entities("sample")
|
|
244
|
+
|
|
245
|
+
def participants(self):
|
|
246
|
+
"""List participants in a workspace."""
|
|
247
|
+
return self.__get_entities("participant")
|
|
248
|
+
|
|
249
|
+
def pairs(self):
|
|
250
|
+
"""List pairs in a workspace."""
|
|
251
|
+
return self.__get_entities("pair")
|
|
252
|
+
|
|
253
|
+
def sample_sets(self):
|
|
254
|
+
"""List sample sets in a workspace."""
|
|
255
|
+
return self.__get_entities("sample_set")
|
|
256
|
+
|
|
257
|
+
def participant_sets(self):
|
|
258
|
+
"""List participant sets in a workspace."""
|
|
259
|
+
return self.__get_entities("participant_set")
|
|
260
|
+
|
|
261
|
+
def pair_sets(self):
|
|
262
|
+
"""List pair sets in a workspace."""
|
|
263
|
+
return self.__get_entities("pair_set")
|
|
264
|
+
|
|
265
|
+
def copy_entities(self, from_namespace, from_workspace, etype, enames):
|
|
266
|
+
"""Copy entities from another workspace.
|
|
267
|
+
|
|
268
|
+
Args:
|
|
269
|
+
from_namespace (str): Source workspace namespace
|
|
270
|
+
from_workspace (str): Source workspace name
|
|
271
|
+
etype (str): Entity type
|
|
272
|
+
enames (list(str)): List of entity names to copy
|
|
273
|
+
"""
|
|
274
|
+
r = fapi.copy_entities(from_namespace, from_workspace,
|
|
275
|
+
self.namespace, self.name, etype, enames,
|
|
276
|
+
self.api_url)
|
|
277
|
+
fapi._check_response_code(r, 201)
|
|
278
|
+
|
|
279
|
+
def configs(self):
|
|
280
|
+
"""Get method configurations in a workspace."""
|
|
281
|
+
raise NotImplementedError
|
|
282
|
+
r = fapi.get_configs(self.namespace, self.name, self.api_url)
|
|
283
|
+
fapi._check_response_code(r, 200)
|
|
284
|
+
cdata = r.json()
|
|
285
|
+
configs = []
|
|
286
|
+
for c in cdata:
|
|
287
|
+
cnamespace = c['namespace']
|
|
288
|
+
cname = c['name']
|
|
289
|
+
root_etype = c['rootEntityType']
|
|
290
|
+
method_namespace = c['methodRepoMethod']['methodNamespace']
|
|
291
|
+
method_name = c['methodRepoMethod']['methodName']
|
|
292
|
+
method_version = c['methodRepoMethod']['methodVersion']
|
|
293
|
+
|
|
294
|
+
def acl(self):
|
|
295
|
+
"""Get the access control list for this workspace."""
|
|
296
|
+
r = fapi.get_workspace_acl(self.namespace, self.name, self.api_url)
|
|
297
|
+
fapi._check_response_code(r, 200)
|
|
298
|
+
return r.json()
|
|
299
|
+
|
|
300
|
+
def set_acl(self, role, users):
|
|
301
|
+
"""Set access permissions for this workspace
|
|
302
|
+
|
|
303
|
+
Args:
|
|
304
|
+
role (str): Access level
|
|
305
|
+
one of {one of "OWNER", "READER", "WRITER", "NO ACCESS"}
|
|
306
|
+
users (list(str)): List of users to give role to
|
|
307
|
+
"""
|
|
308
|
+
acl_updates = [{"email": user, "accessLevel": role} for user in users]
|
|
309
|
+
r = fapi.update_workspace_acl(self.namespace, self.name,
|
|
310
|
+
acl_updates, self.api_url)
|
|
311
|
+
fapi._check_response_code(r, 200)
|
|
312
|
+
|
|
313
|
+
def clone(self, to_namespace, to_name):
|
|
314
|
+
"""Clone this workspace.
|
|
315
|
+
|
|
316
|
+
Args:
|
|
317
|
+
to_namespace (str): Target workspace namespace
|
|
318
|
+
to_name (str): Target workspace name
|
|
319
|
+
"""
|
|
320
|
+
r = fapi.clone_workspace(self.namespace, self.name,
|
|
321
|
+
to_namespace, to_name, self.api_url)
|
|
322
|
+
fapi._check_response_code(r, 201)
|
|
323
|
+
return Workspace(to_namespace, to_name, self.api_url)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: firecloud-api-cds
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Fork of broadinstitute/fiss
|
|
5
|
+
Project-URL: Homepage, https://github.com/broadinstitute/firecloud-api-cds
|
|
6
|
+
License: BSD 3-Clause License
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Requires-Python: >=3.9
|
|
9
|
+
Requires-Dist: google-auth!=2.1.*,!=2.2.*,!=2.3.0,!=2.3.1,>=1.6.3
|
|
10
|
+
Requires-Dist: google-cloud-storage>=1.36.1
|
|
11
|
+
Requires-Dist: pydot>=4.0.0
|
|
12
|
+
Requires-Dist: six>=1.17.0
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
|
|
15
|
+
firecloud-api-cds
|
|
16
|
+
===
|
|
17
|
+
|
|
18
|
+
Fork of [https://github.com/broadinstitute/fiss](https://github.com/broadinstitute/fiss).
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
firecloud_api_cds/__init__.py,sha256=uhUFQxF7jtpCBtdxOkSpOTaSr-h5-fGfWYYknmNxHBE,250
|
|
2
|
+
firecloud_api_cds/api.py,sha256=FOdCgHeygUXl1R6YNXar2z2ljI02K8AC-1WbZgswFew,62555
|
|
3
|
+
firecloud_api_cds/config.py,sha256=B2fmheEVIe-8QSwaItueKceJqD68LB6qfrWSmAz4EW8,729
|
|
4
|
+
firecloud_api_cds/entity.py,sha256=W2vA7Te__HKr_l6IJq-1ThfNLfluCL_HbFPdk_tFCno,2402
|
|
5
|
+
firecloud_api_cds/errors.py,sha256=1vQITDBz3tXOTTH8ptjR26RerIdB3AzEF6An6XF4QhA,470
|
|
6
|
+
firecloud_api_cds/fccore.py,sha256=0KY9wf6LSZVlwBlar7EHKJ66zvbfHLr6RIV8kf3HKg4,7276
|
|
7
|
+
firecloud_api_cds/fiss.py,sha256=TQS8gbWbQ0CYWhqhO85wlUNDE6Rm_KneuF2WX4ZF-8c,127761
|
|
8
|
+
firecloud_api_cds/method.py,sha256=EvfzTUtwfbWKRV22deLhS8zPdNx_7qlSKD7YJM9b1Hs,3055
|
|
9
|
+
firecloud_api_cds/submission.py,sha256=QWXG5Qg8-t3oMOquVnq8Aiq3lfO54LRbZcP_ACYF-aQ,1130
|
|
10
|
+
firecloud_api_cds/supervisor.py,sha256=-z7eTDze4778XC305ndbItjzDCCD2c_KrikPu5At9yg,11982
|
|
11
|
+
firecloud_api_cds/workspace.py,sha256=_SIEQzCZweDPHG6_xGRoJQ0Rg6pHCTT49aKDKAQOwO0,11502
|
|
12
|
+
firecloud_api_cds-0.2.0.dist-info/METADATA,sha256=VjA52NQovI8cZJoG9kWyry0DytjOCqDHW2vPdgi7NCE,567
|
|
13
|
+
firecloud_api_cds-0.2.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
14
|
+
firecloud_api_cds-0.2.0.dist-info/licenses/LICENSE,sha256=ZKuWQRVyyGZq9eYztaCgDoPHgnlFv6beDxmHGwcyQtE,1525
|
|
15
|
+
firecloud_api_cds-0.2.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2018, Broad Institute, Inc.
|
|
4
|
+
All rights reserved.
|
|
5
|
+
|
|
6
|
+
Redistribution and use in source and binary forms, with or without
|
|
7
|
+
modification, are permitted provided that the following conditions are met:
|
|
8
|
+
|
|
9
|
+
* Redistributions of source code must retain the above copyright notice, this
|
|
10
|
+
list of conditions and the following disclaimer.
|
|
11
|
+
|
|
12
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
|
13
|
+
this list of conditions and the following disclaimer in the documentation
|
|
14
|
+
and/or other materials provided with the distribution.
|
|
15
|
+
|
|
16
|
+
* Neither the name Broad Institute, Inc. nor the names of its
|
|
17
|
+
contributors may be used to endorse or promote products derived from
|
|
18
|
+
this software without specific prior written permission.
|
|
19
|
+
|
|
20
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
21
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
22
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
23
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
24
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
25
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
26
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
27
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
28
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
29
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
30
|
+
|