Skip to content

Commit e35cfa0

Browse files
committed
Define experiment API
- Declares load_batch, save_batch functions
1 parent 18d0b46 commit e35cfa0

File tree

1 file changed

+252
-0
lines changed

1 file changed

+252
-0
lines changed

labkey/experiment.py

Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
#
2+
# Copyright (c) 2015 LabKey Corporation
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
#
16+
from __future__ import unicode_literals
17+
import json
18+
19+
from requests.exceptions import SSLError
20+
from utils import build_url, handle_response
21+
22+
23+
# EXAMPLE
24+
# -------
25+
26+
# from utils import create_server_context
27+
# from experiment import load_batch, save_batch
28+
#
29+
# print("Create a server context")
30+
# server_context = create_server_context('localhost:8080', 'CDSTest Project', 'labkey', use_ssl=False)
31+
#
32+
# print("Load an Assay batch from the server")
33+
# assay_id = # provide one from your server
34+
# batch_id = # provide one from your server
35+
# run_group = load_batch(assay_id, batch_id, server_context)
36+
#
37+
# if run_group is not None:
38+
# print("Batch Id: " + str(run_group.id))
39+
# print("Created By: " + run_group.created_by)
40+
#
41+
# print("Modify a property")
42+
# batch_property_name = '' # provide one from your assay
43+
# batch_property_value = '' # provide one
44+
# run_group.properties[batch_property_name] = batch_property_value
45+
#
46+
# print("Save the batch")
47+
# save_batch(assay_id, run_group, server_context)
48+
49+
# --------
50+
# /EXAMPLE
51+
52+
# TODO Incorporate logging
53+
54+
def load_batch(assay_id, batch_id, server_context):
55+
"""
56+
Loads a batch from the server.
57+
:param assay_id: The protocol id of the assay from which to load a batch.
58+
:param batch_id:
59+
:param server_context: A LabKey server context. See utils.create_server_context.
60+
:return:
61+
"""
62+
load_batch_url = build_url('assay', 'getAssayBatch.api', server_context)
63+
session = server_context['session']
64+
65+
payload = {
66+
'assayId': assay_id,
67+
'batchId': batch_id
68+
}
69+
70+
headers = {
71+
'Content-type': 'application/json',
72+
'Accept': 'text/plain'
73+
}
74+
75+
try:
76+
response = session.post(load_batch_url, data=json.dumps(payload), headers=headers)
77+
json_body = handle_response(response)
78+
if json_body is not None:
79+
return Batch.from_data(json_body['batch'])
80+
except SSLError as e:
81+
raise Exception("Failed to match server SSL configuration. Failed to load batch.")
82+
83+
return None
84+
85+
86+
def save_batch(assay_id, batch, server_context):
87+
"""
88+
Saves a modified batch.
89+
:param assay_id: The assay protocol id.
90+
:param batch: The Batch to save.
91+
:param server_context: A LabKey server context. See utils.create_server_context.
92+
:return:
93+
"""
94+
if not isinstance(batch, Batch):
95+
raise Exception('save_batch() "batch" expected to be instance of Batch')
96+
97+
save_batch_url = build_url('assay', 'saveAssayBatch.api', server_context)
98+
session = server_context['session']
99+
payload = {
100+
'assayId': assay_id,
101+
'batches': [batch.to_json()]
102+
}
103+
headers = {
104+
'Content-type': 'application/json',
105+
'Accept': 'text/plain'
106+
}
107+
108+
try:
109+
# print(payload)
110+
response = session.post(save_batch_url, data=json.dumps(payload), headers=headers)
111+
json_body = handle_response(response)
112+
if json_body is not None:
113+
return Batch.from_data(json_body['batch'])
114+
except SSLError as e:
115+
raise Exception("Failed to match server SSL configuration. Failed to save batch.")
116+
117+
return None
118+
119+
120+
class ExpObject(object):
121+
def __init__(self, **kwargs):
122+
self.lsid = kwargs.pop('lsid', None)
123+
self.name = kwargs.pop('name', None)
124+
self.id = kwargs.pop('id', 0)
125+
self.row_id = self.id
126+
self.comment = kwargs.pop('comment', None)
127+
self.created = kwargs.pop('created', None)
128+
self.modified = kwargs.pop('modified', None)
129+
self.created_by = kwargs.pop('created_by', kwargs.pop('createdBy', None))
130+
self.modified_by = kwargs.pop('modified_by', kwargs.pop('modifiedBy', None))
131+
self.properties = kwargs.pop('properties', {})
132+
133+
def to_json(self):
134+
data = {
135+
'id': self.id,
136+
'lsid': self.lsid,
137+
'comment': self.comment,
138+
'name': self.name,
139+
'created': self.created,
140+
'createdBy': self.created_by,
141+
'modified': self.modified,
142+
'modifiedBy': self.modified_by,
143+
'properties': self.properties
144+
}
145+
return data
146+
147+
148+
# TODO: Move these classes into their own file(s)
149+
class Batch(ExpObject):
150+
def __init__(self, **kwargs):
151+
super(Batch, self).__init__(**kwargs)
152+
153+
self.batch_protocol_id = kwargs.pop('batch_protocol_id', self.id)
154+
self.hidden = kwargs.pop('hidden', False)
155+
156+
runs = kwargs.pop('runs', [])
157+
run_instances = []
158+
159+
for run in runs:
160+
run_instances.append(Run.from_data(run))
161+
162+
self.runs = run_instances
163+
164+
@staticmethod
165+
def from_data(data):
166+
return Batch(**data)
167+
168+
def to_json(self):
169+
170+
data = super(Batch, self).to_json()
171+
172+
json_runs = []
173+
for run in self.runs:
174+
json_runs.append(run.to_json())
175+
176+
# The JavaScript API doesn't appear to send these?
177+
# data['batchProtocolId'] = self.batch_protocol_id
178+
# data['hidden'] = self.hidden
179+
data['runs'] = json_runs
180+
181+
return data
182+
183+
184+
class Run(ExpObject):
185+
def __init__(self, **kwargs):
186+
super(Run, self).__init__(**kwargs)
187+
188+
self.experiments = kwargs.pop('experiments', [])
189+
self.file_path_root = kwargs.pop('file_path_root', kwargs.pop('filePathRoot', None))
190+
self.protocol = kwargs.pop('protocol', None)
191+
self.data_outputs = kwargs.pop('data_outputs', kwargs.pop('dataOutputs', []))
192+
self.data_rows = kwargs.pop('data_rows', kwargs.pop('dataRows', []))
193+
self.material_inputs = kwargs.pop('material_inputs', kwargs.pop('materialInputs', []))
194+
self.material_outputs = kwargs.pop('material_outputs', kwargs.pop('materialOutputs', []))
195+
self.object_properties = kwargs.pop('object_properties', kwargs.pop('objectProperties', []))
196+
197+
# TODO: initialize protocol
198+
# self._protocol = None
199+
200+
# initialize data_inputs
201+
data_inputs = kwargs.pop('data_inputs', kwargs.pop('dataInputs', []))
202+
data_inputs_instances = []
203+
204+
for input in data_inputs:
205+
data_inputs_instances.append(Data.from_data(input))
206+
207+
self.data_inputs = data_inputs_instances
208+
209+
@staticmethod
210+
def from_data(data):
211+
return Run(**data)
212+
213+
def to_json(self):
214+
data = super(Run, self).to_json()
215+
216+
data['dataInputs'] = self.data_inputs
217+
data['dataRows'] = self.data_rows
218+
data['experiments'] = self.experiments
219+
data['filePathRoot'] = self.file_path_root
220+
data['materialInputs'] = self.material_inputs
221+
data['materialOutputs'] = self.material_outputs
222+
223+
return data
224+
225+
226+
class ProtocolOutput(ExpObject):
227+
def __init__(self, **kwargs):
228+
super(ProtocolOutput, self).__init__(**kwargs)
229+
230+
self.source_protocol = kwargs.pop('source_protocol', kwargs.pop('sourceProtocol', None))
231+
self.run = kwargs.pop('run', None) # TODO Check if this should be a Run instance
232+
self.target_applications = kwargs.pop('target_applications', kwargs.pop('targetApplications'), None)
233+
self.successor_runs = kwargs.pop('successor_runs', kwargs.pop('sucessorRuns', None)) # sic
234+
self.cpas_type = kwargs.pop('cpas_type', kwargs.pop('cpasType', None))
235+
236+
@staticmethod
237+
def from_data(data):
238+
return ProtocolOutput(**data)
239+
240+
241+
class Data(ProtocolOutput):
242+
def __init__(self, **kwargs):
243+
super(Data, self).__init__(**kwargs)
244+
245+
self.data_type = kwargs.pop('data_type', kwargs.pop('dataType', None))
246+
self.data_file_url = kwargs.pop('data_file_url', kwargs.pop('dataFileURL', None))
247+
self.pipeline_path = kwargs.pop('pipeline_path', kwargs.pop('pipeline_path', None))
248+
self.role = kwargs.pop('role', None)
249+
250+
@staticmethod
251+
def from_data(data):
252+
return Data(**data)

0 commit comments

Comments
 (0)