pychemstation 0.5.8__py3-none-any.whl → 0.5.10__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.
- pychemstation/control/controllers/method.py +130 -92
- pychemstation/control/controllers/sequence.py +15 -48
- pychemstation/control/controllers/table_controller.py +59 -8
- pychemstation/control/hplc.py +30 -44
- pychemstation/utils/macro.py +6 -0
- pychemstation/utils/method_types.py +17 -8
- pychemstation/utils/sequence_types.py +2 -2
- pychemstation/utils/table_types.py +3 -0
- pychemstation/utils/tray_types.py +37 -1
- {pychemstation-0.5.8.dist-info → pychemstation-0.5.10.dist-info}/METADATA +1 -1
- {pychemstation-0.5.8.dist-info → pychemstation-0.5.10.dist-info}/RECORD +19 -19
- tests/constants.py +15 -15
- tests/test_comb.py +37 -44
- tests/test_comm.py +1 -14
- tests/test_method.py +7 -7
- tests/test_sequence.py +7 -7
- {pychemstation-0.5.8.dist-info → pychemstation-0.5.10.dist-info}/LICENSE +0 -0
- {pychemstation-0.5.8.dist-info → pychemstation-0.5.10.dist-info}/WHEEL +0 -0
- {pychemstation-0.5.8.dist-info → pychemstation-0.5.10.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
import os
|
2
2
|
import time
|
3
|
-
from typing import Optional
|
3
|
+
from typing import Optional, Union
|
4
4
|
|
5
5
|
from xsdata.formats.dataclass.parsers import XmlParser
|
6
6
|
|
@@ -9,7 +9,7 @@ from ...control.controllers.comm import CommunicationController
|
|
9
9
|
from ...generated import PumpMethod, DadMethod, SolventElement
|
10
10
|
from ...utils.chromatogram import TIME_FORMAT, AgilentChannelChromatogramData
|
11
11
|
from ...utils.macro import Command
|
12
|
-
from ...utils.method_types import PType, TimeTableEntry, Param,
|
12
|
+
from ...utils.method_types import PType, TimeTableEntry, Param, MethodDetails, HPLCMethodParams
|
13
13
|
from ...utils.table_types import RegisterFlag, TableOperation, Table
|
14
14
|
|
15
15
|
|
@@ -43,30 +43,53 @@ class MethodController(TableController):
|
|
43
43
|
register_flag=RegisterFlag.FLOW
|
44
44
|
)
|
45
45
|
),
|
46
|
-
maximum_run_time=self.controller.get_num_val(
|
47
|
-
cmd=TableOperation.GET_OBJ_HDR_VAL.value.format(
|
48
|
-
register=self.table.register,
|
49
|
-
register_flag=RegisterFlag.MAX_TIME
|
50
|
-
)
|
51
|
-
),
|
52
46
|
)
|
53
47
|
|
54
48
|
def get_row(self, row: int) -> TimeTableEntry:
|
55
49
|
return TimeTableEntry(start_time=self.get_num(row, RegisterFlag.TIME),
|
56
50
|
organic_modifer=self.get_num(row, RegisterFlag.TIMETABLE_SOLVENT_B_COMPOSITION),
|
57
|
-
flow=
|
58
|
-
|
59
|
-
def
|
51
|
+
flow=self.get_num(row, RegisterFlag.TIMETABLE_FLOW))
|
52
|
+
|
53
|
+
def get_timetable(self, rows: int):
|
54
|
+
uncoalesced_timetable_rows = [self.get_row(r + 1) for r in range(rows)]
|
55
|
+
timetable_rows = {}
|
56
|
+
for row in uncoalesced_timetable_rows:
|
57
|
+
time_key = str(row.start_time)
|
58
|
+
if time_key not in timetable_rows.keys():
|
59
|
+
timetable_rows[time_key] = TimeTableEntry(start_time=row.start_time,
|
60
|
+
flow=row.flow,
|
61
|
+
organic_modifer=row.organic_modifer)
|
62
|
+
else:
|
63
|
+
if row.flow:
|
64
|
+
timetable_rows[time_key].flow = row.flow
|
65
|
+
if row.organic_modifer:
|
66
|
+
timetable_rows[time_key].organic_modifer = row.organic_modifer
|
67
|
+
entries = list(timetable_rows.values())
|
68
|
+
entries.sort(key=lambda e: e.start_time)
|
69
|
+
return entries
|
70
|
+
|
71
|
+
def load(self) -> MethodDetails:
|
60
72
|
rows = self.get_num_rows()
|
61
73
|
if rows.is_ok():
|
62
74
|
self.send(Command.GET_METHOD_CMD)
|
63
75
|
res = self.receive()
|
64
76
|
method_name = res.ok_value.string_response
|
65
|
-
timetable_rows =
|
66
|
-
|
77
|
+
timetable_rows = self.get_timetable(int(rows.ok_value.num_response))
|
78
|
+
params = self.get_method_params()
|
79
|
+
stop_time = self.controller.get_num_val(
|
80
|
+
cmd=TableOperation.GET_OBJ_HDR_VAL.value.format(
|
81
|
+
register=self.table.register,
|
82
|
+
register_flag=RegisterFlag.MAX_TIME))
|
83
|
+
post_time = self.controller.get_num_val(
|
84
|
+
cmd=TableOperation.GET_OBJ_HDR_VAL.value.format(
|
85
|
+
register=self.table.register,
|
86
|
+
register_flag=RegisterFlag.POST_TIME))
|
87
|
+
self.table_state = MethodDetails(
|
67
88
|
name=method_name,
|
68
|
-
|
69
|
-
|
89
|
+
timetable=timetable_rows,
|
90
|
+
stop_time=stop_time,
|
91
|
+
post_time=post_time,
|
92
|
+
params=params)
|
70
93
|
return self.table_state
|
71
94
|
else:
|
72
95
|
raise RuntimeError(rows.err_value)
|
@@ -104,7 +127,7 @@ class MethodController(TableController):
|
|
104
127
|
assert parsed_response == f"{method_name}.M", "Switching Methods failed."
|
105
128
|
self.table_state = None
|
106
129
|
|
107
|
-
def load_from_disk(self, method_name: str) ->
|
130
|
+
def load_from_disk(self, method_name: str) -> MethodDetails:
|
108
131
|
"""
|
109
132
|
Retrieve method details of an existing method. Don't need to append ".M" to the end. This assumes the
|
110
133
|
organic modifier is in Channel B and that Channel A contains the aq layer. Additionally, assumes
|
@@ -133,105 +156,69 @@ class MethodController(TableController):
|
|
133
156
|
elif solvent.channel == "Channel_B":
|
134
157
|
organic_modifier = solvent
|
135
158
|
|
136
|
-
self.table_state =
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
],
|
148
|
-
dad_wavelengthes=dad.signals.signal,
|
149
|
-
organic_modifier=organic_modifier,
|
150
|
-
modifier_a=aq_modifier
|
151
|
-
)
|
159
|
+
self.table_state = MethodDetails(
|
160
|
+
name=method_name,
|
161
|
+
params=HPLCMethodParams(organic_modifier=organic_modifier.percentage,
|
162
|
+
flow=method.flow),
|
163
|
+
stop_time=method.stop_time.stop_time_value,
|
164
|
+
post_time=method.post_time.post_time_value,
|
165
|
+
timetable=[TimeTableEntry(start_time=tte.time,
|
166
|
+
organic_modifer=tte.percent_b,
|
167
|
+
flow=method.flow
|
168
|
+
) for tte in method.timetable.timetable_entry],
|
169
|
+
dad_wavelengthes=dad.signals.signal)
|
152
170
|
return self.table_state
|
153
171
|
else:
|
154
172
|
raise FileNotFoundError
|
155
173
|
|
156
|
-
def edit(self, updated_method:
|
174
|
+
def edit(self, updated_method: MethodDetails, save: bool):
|
157
175
|
"""Updated the currently loaded method in ChemStation with provided values.
|
158
176
|
|
159
177
|
:param updated_method: the method with updated values, to be sent to Chemstation to modify the currently loaded method.
|
178
|
+
:param save: if false only modifies the method, otherwise saves to disk
|
160
179
|
"""
|
161
180
|
self.table_state = updated_method
|
162
|
-
initial_organic_modifier: Param = Param(val=updated_method.
|
181
|
+
initial_organic_modifier: Param = Param(val=updated_method.params.organic_modifier,
|
163
182
|
chemstation_key=RegisterFlag.SOLVENT_B_COMPOSITION,
|
164
183
|
ptype=PType.NUM)
|
165
|
-
max_time: Param = Param(val=updated_method.
|
184
|
+
max_time: Param = Param(val=updated_method.stop_time,
|
166
185
|
chemstation_key=RegisterFlag.MAX_TIME,
|
167
186
|
ptype=PType.NUM)
|
168
|
-
|
187
|
+
post_time: Param = Param(val=updated_method.post_time,
|
188
|
+
chemstation_key=RegisterFlag.POST_TIME,
|
189
|
+
ptype=PType.NUM) # TODO check postime works
|
190
|
+
flow: Param = Param(val=updated_method.params.flow,
|
169
191
|
chemstation_key=RegisterFlag.FLOW,
|
170
192
|
ptype=PType.NUM)
|
171
193
|
|
172
194
|
# Method settings required for all runs
|
173
|
-
self.
|
174
|
-
self.
|
175
|
-
self._update_param(flow)
|
176
|
-
self._update_param(Param(val="Set",
|
177
|
-
chemstation_key=RegisterFlag.STOPTIME_MODE,
|
178
|
-
ptype=PType.STR))
|
179
|
-
self._update_param(max_time)
|
180
|
-
self._update_param(Param(val="Off",
|
181
|
-
chemstation_key=RegisterFlag.POSTIME_MODE,
|
182
|
-
ptype=PType.STR))
|
183
|
-
|
184
|
-
self.send("DownloadRCMethod PMP1")
|
185
|
-
|
186
|
-
self._update_method_timetable(updated_method.subsequent_rows)
|
195
|
+
self.update_method_params(flow, initial_organic_modifier, max_time, post_time)
|
196
|
+
self._update_method_timetable(updated_method.timetable)
|
187
197
|
|
188
198
|
if save:
|
189
199
|
self.send(Command.SAVE_METHOD_CMD.value.format(
|
190
200
|
commit_msg=f"saved method at {str(time.time())}"
|
191
201
|
))
|
192
202
|
|
193
|
-
def
|
194
|
-
self.
|
195
|
-
self.
|
196
|
-
|
197
|
-
self.
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
self.sleepy_send('NewColText RCPMP1Method[1], "Timetable", "Function", "SolventComposition"')
|
213
|
-
self.sleepy_send(f'NewColVal RCPMP1Method[1], "Timetable", "Time", {row.start_time}')
|
214
|
-
self.sleepy_send(
|
215
|
-
f'NewColVal RCPMP1Method[1], "Timetable", "SolventCompositionPumpChannel2_Percentage", {row.organic_modifer}')
|
216
|
-
|
217
|
-
self.send('Sleep 1')
|
218
|
-
self.sleepy_send("DownloadRCMethod PMP1")
|
219
|
-
self.send('Sleep 1')
|
220
|
-
else:
|
221
|
-
self.sleepy_send('InsTabRow RCPMP1Method[1], "Timetable"')
|
222
|
-
self.get_num_rows()
|
223
|
-
|
224
|
-
self.sleepy_send(
|
225
|
-
f'SetTabText RCPMP1Method[1], "Timetable", Rows, "Function", "SolventComposition"')
|
226
|
-
self.sleepy_send(
|
227
|
-
f'SetTabVal RCPMP1Method[1], "Timetable", Rows, "Time", {row.start_time}')
|
228
|
-
self.sleepy_send(
|
229
|
-
f'SetTabVal RCPMP1Method[1], "Timetable", Rows, "SolventCompositionPumpChannel2_Percentage", {row.organic_modifer}')
|
230
|
-
|
231
|
-
self.send("Sleep 1")
|
232
|
-
self.sleepy_send("DownloadRCMethod PMP1")
|
233
|
-
self.send("Sleep 1")
|
234
|
-
self.get_num_rows()
|
203
|
+
def update_method_params(self, flow, initial_organic_modifier, max_time, post_time):
|
204
|
+
self.delete_table()
|
205
|
+
self._update_param(initial_organic_modifier)
|
206
|
+
self._update_param(flow)
|
207
|
+
if self.table_state.stop_time:
|
208
|
+
self._update_param(Param(val="Set",
|
209
|
+
chemstation_key=RegisterFlag.STOPTIME_MODE,
|
210
|
+
ptype=PType.STR))
|
211
|
+
self._update_param(max_time)
|
212
|
+
else:
|
213
|
+
self._update_param(Param(val="Off",
|
214
|
+
chemstation_key=RegisterFlag.STOPTIME_MODE,
|
215
|
+
ptype=PType.STR))
|
216
|
+
if self.table_state.post_time:
|
217
|
+
self._update_param(Param(val="Set",
|
218
|
+
chemstation_key=RegisterFlag.POSTIME_MODE,
|
219
|
+
ptype=PType.STR))
|
220
|
+
self._update_param(post_time)
|
221
|
+
self.download()
|
235
222
|
|
236
223
|
def _update_param(self, method_param: Param):
|
237
224
|
"""Change a method parameter, changes what is visibly seen in Chemstation GUI.
|
@@ -252,6 +239,57 @@ class MethodController(TableController):
|
|
252
239
|
val=method_param.val))
|
253
240
|
time.sleep(2)
|
254
241
|
|
242
|
+
def download(self):
|
243
|
+
self.send('Sleep 1')
|
244
|
+
self.sleepy_send("DownloadRCMethod PMP1")
|
245
|
+
self.send('Sleep 1')
|
246
|
+
|
247
|
+
def edit_row(self, row: TimeTableEntry, first_row: bool = False):
|
248
|
+
if first_row:
|
249
|
+
self.add_row()
|
250
|
+
self.add_new_col_text(col_name=RegisterFlag.FUNCTION,
|
251
|
+
val=RegisterFlag.SOLVENT_COMPOSITION.value)
|
252
|
+
self.add_new_col_num(col_name=RegisterFlag.TIME, val=row.start_time)
|
253
|
+
self.add_new_col_num(col_name=RegisterFlag.TIMETABLE_SOLVENT_B_COMPOSITION,
|
254
|
+
val=row.organic_modifer)
|
255
|
+
self.add_row()
|
256
|
+
self.get_num_rows()
|
257
|
+
self.edit_row_text(col_name=RegisterFlag.FUNCTION, val=RegisterFlag.FLOW.value)
|
258
|
+
self.add_new_col_num(col_name=RegisterFlag.TIMETABLE_FLOW, val=row.flow)
|
259
|
+
self.edit_row_num(col_name=RegisterFlag.TIMETABLE_FLOW, val=row.flow)
|
260
|
+
self.download()
|
261
|
+
else:
|
262
|
+
self.add_row()
|
263
|
+
self.get_num_rows()
|
264
|
+
self.edit_row_text(col_name=RegisterFlag.FUNCTION,
|
265
|
+
val=RegisterFlag.SOLVENT_COMPOSITION.value)
|
266
|
+
self.edit_row_num(col_name=RegisterFlag.TIME, val=row.start_time)
|
267
|
+
self.edit_row_num(col_name=RegisterFlag.TIMETABLE_SOLVENT_B_COMPOSITION,
|
268
|
+
val=row.organic_modifer)
|
269
|
+
self.download()
|
270
|
+
|
271
|
+
self.add_row()
|
272
|
+
self.get_num_rows()
|
273
|
+
self.edit_row_text(col_name=RegisterFlag.FUNCTION, val=RegisterFlag.FLOW.value)
|
274
|
+
self.edit_row_num(col_name=RegisterFlag.TIMETABLE_FLOW, val=row.flow)
|
275
|
+
self.edit_row_num(col_name=RegisterFlag.TIME, val=row.start_time)
|
276
|
+
self.download()
|
277
|
+
|
278
|
+
def _update_method_timetable(self, timetable_rows: list[TimeTableEntry]):
|
279
|
+
self.get_num_rows()
|
280
|
+
|
281
|
+
self.delete_table()
|
282
|
+
res = self.get_num_rows()
|
283
|
+
while not res.is_err():
|
284
|
+
self.delete_table()
|
285
|
+
res = self.get_num_rows()
|
286
|
+
|
287
|
+
self.new_table()
|
288
|
+
self.get_num_rows()
|
289
|
+
|
290
|
+
for i, row in enumerate(timetable_rows):
|
291
|
+
self.edit_row(row=row, first_row=i == 0)
|
292
|
+
|
255
293
|
def stop(self):
|
256
294
|
"""
|
257
295
|
Stops the method run. A dialog window will pop up and manual intervention may be required.\
|
@@ -1,5 +1,4 @@
|
|
1
|
-
from typing import
|
2
|
-
|
1
|
+
from typing import Optional
|
3
2
|
|
4
3
|
import os
|
5
4
|
import time
|
@@ -10,6 +9,7 @@ from ...utils.chromatogram import SEQUENCE_TIME_FORMAT, AgilentChannelChromatogr
|
|
10
9
|
from ...utils.macro import Command
|
11
10
|
from ...utils.sequence_types import SequenceTable, SequenceEntry, SequenceDataFiles, InjectionSource, SampleType
|
12
11
|
from ...utils.table_types import TableOperation, RegisterFlag, Table
|
12
|
+
from ...utils.tray_types import TenColumn
|
13
13
|
|
14
14
|
|
15
15
|
class SequenceController(TableController):
|
@@ -47,7 +47,7 @@ class SequenceController(TableController):
|
|
47
47
|
num_inj=num_inj,
|
48
48
|
inj_vol=inj_vol,
|
49
49
|
inj_source=inj_source,
|
50
|
-
sample_type=sample_type
|
50
|
+
sample_type=sample_type)
|
51
51
|
|
52
52
|
def check(self) -> str:
|
53
53
|
time.sleep(2)
|
@@ -116,67 +116,34 @@ class SequenceController(TableController):
|
|
116
116
|
self.send(Command.SAVE_SEQUENCE_CMD)
|
117
117
|
num_rows = self.get_num_rows()
|
118
118
|
|
119
|
-
table_register = self.table.register
|
120
|
-
table_name = self.table.name
|
121
|
-
|
122
119
|
if row.vial_location:
|
123
120
|
loc = row.vial_location
|
124
|
-
if isinstance(row.vial_location,
|
121
|
+
if isinstance(row.vial_location, TenColumn):
|
125
122
|
loc = row.vial_location.value
|
126
|
-
self.
|
127
|
-
|
128
|
-
row=row_num,
|
129
|
-
col_name=RegisterFlag.VIAL_LOCATION,
|
130
|
-
val=loc))
|
123
|
+
self.edit_row_num(row=row_num, col_name=RegisterFlag.VIAL_LOCATION, val=loc)
|
124
|
+
|
131
125
|
if row.method:
|
132
126
|
possible_path = os.path.join(self.method_dir, row.method) + ".M\\"
|
133
127
|
method = row.method
|
134
128
|
if os.path.exists(possible_path):
|
135
129
|
method = os.path.join(self.method_dir, row.method)
|
136
|
-
self.
|
137
|
-
table_name=table_name,
|
138
|
-
row=row_num,
|
139
|
-
col_name=RegisterFlag.METHOD,
|
140
|
-
val=method))
|
130
|
+
self.edit_row_text(row=row_num, col_name=RegisterFlag.METHOD, val=method)
|
141
131
|
|
142
132
|
if row.num_inj:
|
143
|
-
self.
|
144
|
-
table_name=table_name,
|
145
|
-
row=row_num,
|
146
|
-
col_name=RegisterFlag.NUM_INJ,
|
147
|
-
val=row.num_inj))
|
133
|
+
self.edit_row_num(row=row_num, col_name=RegisterFlag.NUM_INJ, val=row.num_inj)
|
148
134
|
|
149
135
|
if row.inj_vol:
|
150
|
-
self.
|
151
|
-
table_name=table_name,
|
152
|
-
row=row_num,
|
153
|
-
col_name=RegisterFlag.INJ_VOL,
|
154
|
-
val=row.inj_vol))
|
136
|
+
self.edit_row_text(row=row_num, col_name=RegisterFlag.INJ_VOL, val=row.inj_vol)
|
155
137
|
|
156
138
|
if row.inj_source:
|
157
|
-
self.
|
158
|
-
table_name=table_name,
|
159
|
-
row=row_num,
|
160
|
-
col_name=RegisterFlag.INJ_SOR,
|
161
|
-
val=row.inj_source.value))
|
139
|
+
self.edit_row_text(row=row_num, col_name=RegisterFlag.INJ_SOR, val=row.inj_source.value)
|
162
140
|
|
163
141
|
if row.sample_name:
|
164
|
-
self.
|
165
|
-
|
166
|
-
|
167
|
-
col_name=RegisterFlag.NAME,
|
168
|
-
val=row.sample_name))
|
169
|
-
self.sleepy_send(TableOperation.EDIT_ROW_TEXT.value.format(register=table_register,
|
170
|
-
table_name=table_name,
|
171
|
-
row=row_num,
|
172
|
-
col_name=RegisterFlag.DATA_FILE,
|
173
|
-
val=row.sample_name))
|
142
|
+
self.edit_row_text(row=row_num, col_name=RegisterFlag.NAME, val=row.sample_name)
|
143
|
+
self.edit_row_text(row=row_num, col_name=RegisterFlag.DATA_FILE, val=row.sample_name)
|
144
|
+
|
174
145
|
if row.sample_type:
|
175
|
-
self.
|
176
|
-
table_name=table_name,
|
177
|
-
row=row_num,
|
178
|
-
col_name=RegisterFlag.SAMPLE_TYPE,
|
179
|
-
val=row.sample_type.value))
|
146
|
+
self.edit_row_num(row=row_num, col_name=RegisterFlag.SAMPLE_TYPE, val=row.sample_type.value)
|
180
147
|
|
181
148
|
self.send(Command.SAVE_SEQUENCE_CMD)
|
182
149
|
|
@@ -210,7 +177,7 @@ class SequenceController(TableController):
|
|
210
177
|
sequence_data_files: SequenceDataFiles = self.data_files[-1]
|
211
178
|
return sequence_data_files.dir
|
212
179
|
|
213
|
-
def get_data(self, custom_path:Optional[str] = None
|
180
|
+
def get_data(self, custom_path: Optional[str] = None) -> list[AgilentChannelChromatogramData]:
|
214
181
|
parent_dir = self.data_files[-1].dir if not custom_path else custom_path
|
215
182
|
subdirs = [x[0] for x in os.walk(self.data_dir)]
|
216
183
|
potential_folders = sorted(list(filter(lambda d: parent_dir in d, subdirs)))
|
@@ -14,19 +14,19 @@ from result import Result, Ok, Err
|
|
14
14
|
from ...control.controllers.comm import CommunicationController
|
15
15
|
from ...utils.chromatogram import AgilentHPLCChromatogram, AgilentChannelChromatogramData
|
16
16
|
from ...utils.macro import Command, HPLCRunningStatus, Response
|
17
|
-
from ...utils.method_types import
|
17
|
+
from ...utils.method_types import MethodDetails
|
18
18
|
from ...utils.sequence_types import SequenceDataFiles, SequenceTable
|
19
19
|
from ...utils.table_types import Table, TableOperation, RegisterFlag
|
20
20
|
|
21
|
+
TableType = Union[MethodDetails, SequenceTable]
|
21
22
|
|
22
|
-
TableType = Union[MethodTimetable, SequenceTable]
|
23
23
|
|
24
24
|
class TableController(abc.ABC):
|
25
25
|
|
26
26
|
def __init__(self, controller: CommunicationController, src: str, data_dir: str, table: Table):
|
27
27
|
self.controller = controller
|
28
28
|
self.table = table
|
29
|
-
self.table_state
|
29
|
+
self.table_state: Optional[TableType] = None
|
30
30
|
|
31
31
|
if os.path.isdir(src):
|
32
32
|
self.src: str = src
|
@@ -38,7 +38,7 @@ class TableController(abc.ABC):
|
|
38
38
|
else:
|
39
39
|
raise FileNotFoundError(f"dir: {data_dir} not found.")
|
40
40
|
|
41
|
-
self.spectra: dict[str, AgilentHPLCChromatogram] = {
|
41
|
+
self.spectra: dict[str, Optional[AgilentHPLCChromatogram]] = {
|
42
42
|
"A": AgilentHPLCChromatogram(self.data_dir),
|
43
43
|
"B": AgilentHPLCChromatogram(self.data_dir),
|
44
44
|
"C": AgilentHPLCChromatogram(self.data_dir),
|
@@ -51,6 +51,9 @@ class TableController(abc.ABC):
|
|
51
51
|
|
52
52
|
self.data_files: Union[list[SequenceDataFiles], list[str]] = []
|
53
53
|
|
54
|
+
# Initialize row counter for table operations
|
55
|
+
self.send('Local Rows')
|
56
|
+
|
54
57
|
def receive(self) -> Result[Response, str]:
|
55
58
|
for _ in range(10):
|
56
59
|
try:
|
@@ -60,6 +63,9 @@ class TableController(abc.ABC):
|
|
60
63
|
return Err("Could not parse response")
|
61
64
|
|
62
65
|
def send(self, cmd: Union[Command, str]):
|
66
|
+
if not self.controller:
|
67
|
+
raise RuntimeError(
|
68
|
+
"Communication controller must be initialized before sending command. It is currently in offline mode.")
|
63
69
|
self.controller.send(cmd)
|
64
70
|
|
65
71
|
def sleepy_send(self, cmd: Union[Command, str]):
|
@@ -85,6 +91,46 @@ class TableController(abc.ABC):
|
|
85
91
|
row=row,
|
86
92
|
col_name=col_name.value))
|
87
93
|
|
94
|
+
def add_new_col_num(self,
|
95
|
+
col_name: RegisterFlag,
|
96
|
+
val: Union[int, float]):
|
97
|
+
self.sleepy_send(TableOperation.NEW_COL_VAL.value.format(
|
98
|
+
register=self.table.register,
|
99
|
+
table_name=self.table.name,
|
100
|
+
col_name=col_name,
|
101
|
+
val=val))
|
102
|
+
|
103
|
+
def add_new_col_text(self,
|
104
|
+
col_name: RegisterFlag,
|
105
|
+
val: str):
|
106
|
+
self.sleepy_send(TableOperation.NEW_COL_TEXT.value.format(
|
107
|
+
register=self.table.register,
|
108
|
+
table_name=self.table.name,
|
109
|
+
col_name=col_name,
|
110
|
+
val=val))
|
111
|
+
|
112
|
+
def edit_row_num(self,
|
113
|
+
col_name: RegisterFlag,
|
114
|
+
val: Union[int, float],
|
115
|
+
row: Optional[int] = None):
|
116
|
+
self.sleepy_send(TableOperation.EDIT_ROW_VAL.value.format(
|
117
|
+
register=self.table.register,
|
118
|
+
table_name=self.table.name,
|
119
|
+
row=row if row is not None else 'Rows',
|
120
|
+
col_name=col_name,
|
121
|
+
val=val))
|
122
|
+
|
123
|
+
def edit_row_text(self,
|
124
|
+
col_name: RegisterFlag,
|
125
|
+
val: str,
|
126
|
+
row: Optional[int] = None):
|
127
|
+
self.sleepy_send(TableOperation.EDIT_ROW_TEXT.value.format(
|
128
|
+
register=self.table.register,
|
129
|
+
table_name=self.table.name,
|
130
|
+
row=row if row is not None else 'Rows',
|
131
|
+
col_name=col_name,
|
132
|
+
val=val))
|
133
|
+
|
88
134
|
@abc.abstractmethod
|
89
135
|
def get_row(self, row: int):
|
90
136
|
pass
|
@@ -150,7 +196,7 @@ class TableController(abc.ABC):
|
|
150
196
|
return started_running
|
151
197
|
|
152
198
|
def check_hplc_done_running(self,
|
153
|
-
method: Optional[
|
199
|
+
method: Optional[MethodDetails] = None,
|
154
200
|
sequence: Optional[SequenceTable] = None) -> Result[str, str]:
|
155
201
|
"""
|
156
202
|
Checks if ChemStation has finished running and can read data back
|
@@ -169,7 +215,7 @@ class TableController(abc.ABC):
|
|
169
215
|
finished_run = polling.poll(
|
170
216
|
lambda: self.controller.check_if_running(),
|
171
217
|
timeout=timeout,
|
172
|
-
step=
|
218
|
+
step=50)
|
173
219
|
|
174
220
|
check_folder = self.fuzzy_match_most_recent_folder(most_recent_folder)
|
175
221
|
if check_folder.is_ok() and finished_run:
|
@@ -178,9 +224,10 @@ class TableController(abc.ABC):
|
|
178
224
|
finished_run = polling.poll(
|
179
225
|
lambda: self.controller.check_if_running(),
|
180
226
|
timeout=timeout,
|
181
|
-
step=
|
227
|
+
step=50)
|
182
228
|
if finished_run:
|
183
229
|
return check_folder
|
230
|
+
return check_folder
|
184
231
|
else:
|
185
232
|
return Err("Run did not complete as expected")
|
186
233
|
|
@@ -212,4 +259,8 @@ class TableController(abc.ABC):
|
|
212
259
|
Load chromatogram for any channel in spectra dictionary.
|
213
260
|
"""
|
214
261
|
for channel, spec in self.spectra.items():
|
215
|
-
|
262
|
+
try:
|
263
|
+
spec.load_spectrum(data_path=data_file, channel=channel)
|
264
|
+
except FileNotFoundError:
|
265
|
+
self.spectra[channel] = None
|
266
|
+
print(f"No data at channel: {channel}")
|
pychemstation/control/hplc.py
CHANGED
@@ -9,7 +9,7 @@ from typing import Union, Optional
|
|
9
9
|
from ..control.controllers import MethodController, SequenceController, CommunicationController
|
10
10
|
from ..utils.chromatogram import AgilentChannelChromatogramData
|
11
11
|
from ..utils.macro import Command, HPLCRunningStatus, HPLCAvailStatus, HPLCErrorStatus, Response
|
12
|
-
from ..utils.method_types import
|
12
|
+
from ..utils.method_types import MethodDetails
|
13
13
|
from ..utils.sequence_types import SequenceTable, SequenceEntry
|
14
14
|
from ..utils.table_types import Table
|
15
15
|
|
@@ -26,6 +26,11 @@ class HPLCController:
|
|
26
26
|
name="SeqTable1"
|
27
27
|
)
|
28
28
|
|
29
|
+
INJECTOR_TABLE = Table(
|
30
|
+
register="_LeoAlsMethod",
|
31
|
+
name="ProgTable"
|
32
|
+
)
|
33
|
+
|
29
34
|
def __init__(self,
|
30
35
|
comm_dir: str,
|
31
36
|
data_dir: str,
|
@@ -51,17 +56,20 @@ class HPLCController:
|
|
51
56
|
|
52
57
|
def send(self, cmd: Union[Command, str]):
|
53
58
|
if not self.comm:
|
54
|
-
raise RuntimeError(
|
59
|
+
raise RuntimeError(
|
60
|
+
"Communication controller must be initialized before sending command. It is currently in offline mode.")
|
55
61
|
self.comm.send(cmd)
|
56
62
|
|
57
63
|
def receive(self) -> Response:
|
58
64
|
if not self.comm:
|
59
|
-
raise RuntimeError(
|
65
|
+
raise RuntimeError(
|
66
|
+
"Communication controller must be initialized before sending command. It is currently in offline mode.")
|
60
67
|
return self.comm.receive().value
|
61
68
|
|
62
69
|
def status(self) -> Union[HPLCRunningStatus | HPLCAvailStatus | HPLCErrorStatus]:
|
63
70
|
if not self.comm:
|
64
|
-
raise RuntimeError(
|
71
|
+
raise RuntimeError(
|
72
|
+
"Communication controller must be initialized before sending command. It is currently in offline mode.")
|
65
73
|
return self.comm.get_status()
|
66
74
|
|
67
75
|
def switch_method(self, method_name: str):
|
@@ -74,8 +82,6 @@ class HPLCController:
|
|
74
82
|
:raises IndexError: Response did not have expected format. Try again.
|
75
83
|
:raises AssertionError: The desired method is not selected. Try again.
|
76
84
|
"""
|
77
|
-
if not self.comm:
|
78
|
-
raise RuntimeError("Communication controller must be initialized before sending command. It is currently in offline mode.")
|
79
85
|
self.method_controller.switch(method_name)
|
80
86
|
|
81
87
|
def switch_sequence(self, sequence_name: str):
|
@@ -85,8 +91,6 @@ class HPLCController:
|
|
85
91
|
|
86
92
|
:param sequence_name: The name of the sequence file
|
87
93
|
"""
|
88
|
-
if not self.comm:
|
89
|
-
raise RuntimeError("Communication controller must be initialized before sending command. It is currently in offline mode.")
|
90
94
|
self.sequence_controller.switch(sequence_name)
|
91
95
|
|
92
96
|
def run_method(self, experiment_name: str, stall_while_running: bool = True):
|
@@ -100,8 +104,6 @@ class HPLCController:
|
|
100
104
|
:param experiment_name: Name of the experiment
|
101
105
|
:param stall_while_running: whether this method should return or stall while HPLC runs.
|
102
106
|
"""
|
103
|
-
if not self.comm:
|
104
|
-
raise RuntimeError("Communication controller must be initialized before sending command. It is currently in offline mode.")
|
105
107
|
self.method_controller.run(experiment_name, stall_while_running)
|
106
108
|
|
107
109
|
def run_sequence(self, stall_while_running: bool = True):
|
@@ -112,29 +114,23 @@ class HPLCController:
|
|
112
114
|
|
113
115
|
:param stall_while_running: whether this method should return or stall while HPLC runs.
|
114
116
|
"""
|
115
|
-
if not self.comm:
|
116
|
-
raise RuntimeError("Communication controller must be initialized before sending command. It is currently in offline mode.")
|
117
117
|
self.sequence_controller.run(stall_while_running=stall_while_running)
|
118
118
|
|
119
|
-
def edit_method(self, updated_method:
|
119
|
+
def edit_method(self, updated_method: MethodDetails, save: bool = False):
|
120
120
|
"""Updated the currently loaded method in ChemStation with provided values.
|
121
121
|
|
122
122
|
:param updated_method: the method with updated values, to be sent to Chemstation to modify the currently loaded method.
|
123
|
-
:param save:
|
123
|
+
:param save: whether this method should be to disk, or just modified.
|
124
124
|
"""
|
125
|
-
if not self.comm:
|
126
|
-
raise RuntimeError("Communication controller must be initialized before sending command. It is currently in offline mode.")
|
127
125
|
self.method_controller.edit(updated_method, save)
|
128
126
|
|
129
127
|
def edit_sequence(self, updated_sequence: SequenceTable):
|
130
128
|
"""
|
131
|
-
Updates the currently loaded sequence table with the provided table.
|
129
|
+
Updates the currently loaded sequence table with the provided table.
|
132
130
|
If you would only like to edit a single row of a sequence table, use `edit_sequence_row` instead.
|
133
131
|
|
134
|
-
:param updated_sequence:
|
132
|
+
:param updated_sequence: The sequence table to be written to the currently loaded sequence table.
|
135
133
|
"""
|
136
|
-
if not self.comm:
|
137
|
-
raise RuntimeError("Communication controller must be initialized before sending command. It is currently in offline mode.")
|
138
134
|
self.sequence_controller.edit(updated_sequence)
|
139
135
|
|
140
136
|
def edit_sequence_row(self, row: SequenceEntry, num: int):
|
@@ -142,21 +138,23 @@ class HPLCController:
|
|
142
138
|
Edits a row in the sequence table. Assumes the row already exists.
|
143
139
|
|
144
140
|
:param row: sequence row entry with updated information
|
145
|
-
:param
|
141
|
+
:param num: the row to edit, based on 1-based indexing
|
146
142
|
"""
|
147
|
-
if not self.comm:
|
148
|
-
raise RuntimeError("Communication controller must be initialized before sending command. It is currently in offline mode.")
|
149
143
|
self.sequence_controller.edit_row(row, num)
|
150
144
|
|
151
145
|
def get_last_run_method_data(self, data: Optional[str] = None) -> AgilentChannelChromatogramData:
|
152
146
|
"""
|
153
147
|
Returns the last run method data.
|
148
|
+
|
149
|
+
:param data: If you want to just load method data but from a file path. This file path must be the complete file path.
|
154
150
|
"""
|
155
151
|
return self.method_controller.get_data(custom_path=data)
|
156
152
|
|
157
153
|
def get_last_run_sequence_data(self, data: Optional[str] = None) -> list[AgilentChannelChromatogramData]:
|
158
154
|
"""
|
159
155
|
Returns data for all rows in the last run sequence data.
|
156
|
+
|
157
|
+
:param data: If you want to just load sequence data but from a file path. This file path must be the complete file path.
|
160
158
|
"""
|
161
159
|
return self.sequence_controller.get_data(custom_path=data)
|
162
160
|
|
@@ -164,66 +162,54 @@ class HPLCController:
|
|
164
162
|
"""
|
165
163
|
Returns the name of the currently loaded sequence.
|
166
164
|
"""
|
167
|
-
if not self.comm:
|
168
|
-
raise RuntimeError("Communication controller must be initialized before sending command. It is currently in offline mode.")
|
169
165
|
return self.sequence_controller.check()
|
170
166
|
|
171
167
|
def check_loaded_method(self) -> str:
|
172
168
|
"""
|
173
169
|
Returns the name of the currently loaded method.
|
174
170
|
"""
|
175
|
-
if not self.comm:
|
176
|
-
raise RuntimeError("Communication controller must be initialized before sending command. It is currently in offline mode.")
|
177
171
|
return self.method_controller.check()
|
178
172
|
|
179
|
-
def load_method(self) ->
|
173
|
+
def load_method(self) -> MethodDetails:
|
180
174
|
"""
|
181
175
|
Returns all details of the currently loaded method, including its timetable.
|
182
176
|
"""
|
183
|
-
if not self.comm:
|
184
|
-
raise RuntimeError("Communication controller must be initialized before sending command. It is currently in offline mode.")
|
185
177
|
return self.method_controller.load()
|
186
178
|
|
187
179
|
def load_sequence(self) -> SequenceTable:
|
188
180
|
"""
|
189
181
|
Returns the currently loaded sequence.
|
190
182
|
"""
|
191
|
-
if not self.comm:
|
192
|
-
raise RuntimeError("Communication controller must be initialized before sending command. It is currently in offline mode.")
|
193
183
|
return self.sequence_controller.load()
|
194
184
|
|
195
185
|
def standby(self):
|
196
186
|
"""Switches all modules in standby mode. All lamps and pumps are switched off."""
|
197
|
-
if not self.comm:
|
198
|
-
raise RuntimeError("Communication controller must be initialized before sending command. It is currently in offline mode.")
|
199
187
|
self.send(Command.STANDBY_CMD)
|
200
188
|
|
201
189
|
def preprun(self):
|
202
190
|
""" Prepares all modules for run. All lamps and pumps are switched on."""
|
203
|
-
if not self.comm:
|
204
|
-
raise RuntimeError("Communication controller must be initialized before sending command. It is currently in offline mode.")
|
205
191
|
self.send(Command.PREPRUN_CMD)
|
206
192
|
|
207
193
|
def lamp_on(self):
|
208
194
|
"""Turns the UV lamp on."""
|
209
|
-
if not self.comm:
|
210
|
-
raise RuntimeError("Communication controller must be initialized before sending command. It is currently in offline mode.")
|
211
195
|
self.send(Command.LAMP_ON_CMD)
|
212
196
|
|
213
197
|
def lamp_off(self):
|
214
198
|
"""Turns the UV lamp off."""
|
215
|
-
if not self.comm:
|
216
|
-
raise RuntimeError("Communication controller must be initialized before sending command. It is currently in offline mode.")
|
217
199
|
self.send(Command.LAMP_OFF_CMD)
|
218
200
|
|
219
201
|
def pump_on(self):
|
220
202
|
"""Turns on the pump on."""
|
221
|
-
if not self.comm:
|
222
|
-
raise RuntimeError("Communication controller must be initialized before sending command. It is currently in offline mode.")
|
223
203
|
self.send(Command.PUMP_ON_CMD)
|
224
204
|
|
225
205
|
def pump_off(self):
|
226
206
|
"""Turns the pump off."""
|
227
|
-
if not self.comm:
|
228
|
-
raise RuntimeError("Communication controller must be initialized before sending command. It is currently in offline mode.")
|
229
207
|
self.send(Command.PUMP_OFF_CMD)
|
208
|
+
|
209
|
+
def instrument_off(self):
|
210
|
+
"""Shuts the entire instrument off, including pumps, lamps, thermostat."""
|
211
|
+
self.send(Command.INSTRUMENT_OFF)
|
212
|
+
|
213
|
+
def instrument_on(self):
|
214
|
+
"""Turns the entire instrument on, including pumps, lamps, thermostat."""
|
215
|
+
self.send(Command.INSTRUMENT_ON)
|
pychemstation/utils/macro.py
CHANGED
@@ -23,10 +23,16 @@ class Command(Enum):
|
|
23
23
|
STANDBY_CMD = "Standby"
|
24
24
|
STOP_MACRO_CMD = "Stop"
|
25
25
|
PREPRUN_CMD = "PrepRun"
|
26
|
+
|
27
|
+
# Instrument Control
|
26
28
|
LAMP_ON_CMD = "LampAll ON"
|
27
29
|
LAMP_OFF_CMD = "LampAll OFF"
|
28
30
|
PUMP_ON_CMD = "PumpAll ON"
|
29
31
|
PUMP_OFF_CMD = "PumpAll OFF"
|
32
|
+
INSTRUMENT_OFF = 'macro "SHUTDOWN.MAC" ,go'
|
33
|
+
INSTRUMENT_ON = 'LIDoOperation "TURN_ON"'
|
34
|
+
|
35
|
+
|
30
36
|
GET_METHOD_CMD = "response$ = _MethFile$"
|
31
37
|
GET_ROWS_CMD = 'response_num = TabHdrVal({register}, "{table_name}", "{col_name}")'
|
32
38
|
SWITCH_METHOD_CMD = 'LoadMethod "{method_dir}", "{method_name}.M"'
|
@@ -3,8 +3,7 @@ from enum import Enum
|
|
3
3
|
from typing import Union, Any, Optional
|
4
4
|
|
5
5
|
from .table_types import RegisterFlag
|
6
|
-
from ..generated import Signal
|
7
|
-
|
6
|
+
from ..generated import Signal
|
8
7
|
|
9
8
|
|
10
9
|
class PType(Enum):
|
@@ -23,7 +22,7 @@ class Param:
|
|
23
22
|
class HPLCMethodParams:
|
24
23
|
organic_modifier: int
|
25
24
|
flow: float
|
26
|
-
|
25
|
+
pressure: Optional[float] = None #TODO: find this
|
27
26
|
|
28
27
|
|
29
28
|
@dataclass
|
@@ -34,10 +33,20 @@ class TimeTableEntry:
|
|
34
33
|
|
35
34
|
|
36
35
|
@dataclass
|
37
|
-
class
|
36
|
+
class MethodDetails:
|
37
|
+
"""An Agilent Chemstation method, TODO is to add MS parameters
|
38
|
+
|
39
|
+
:attribute name: the name of the method, should be the same as the Chemstation method name.
|
40
|
+
:attribute timetable: list of entries in the method timetable
|
41
|
+
:attribute stop_time: the time the method stops running after the last timetable entry.
|
42
|
+
:attribute post_time: the amount of time after the stoptime that the pumps keep running,
|
43
|
+
based on settings in the first row of the timetable.
|
44
|
+
:attribute params: the organic modifier (pump B) and flow rate displayed for the method (the time 0 settings)
|
45
|
+
:attribute dad_wavelengthes:
|
46
|
+
"""
|
38
47
|
name: str
|
39
|
-
|
40
|
-
|
48
|
+
params: HPLCMethodParams
|
49
|
+
timetable: list[TimeTableEntry]
|
50
|
+
stop_time: Optional[int] = None
|
51
|
+
post_time: Optional[int] = None
|
41
52
|
dad_wavelengthes: Optional[list[Signal]] = None
|
42
|
-
organic_modifier: Optional[SolventElement] = None
|
43
|
-
modifier_a: Optional[SolventElement] = None
|
@@ -4,7 +4,7 @@ from dataclasses import dataclass
|
|
4
4
|
from enum import Enum
|
5
5
|
from typing import Optional, Union
|
6
6
|
|
7
|
-
from pychemstation.utils.tray_types import
|
7
|
+
from pychemstation.utils.tray_types import TenVialColumn
|
8
8
|
|
9
9
|
|
10
10
|
@dataclass
|
@@ -39,7 +39,7 @@ class InjectionSource(Enum):
|
|
39
39
|
@dataclass
|
40
40
|
class SequenceEntry:
|
41
41
|
sample_name: str
|
42
|
-
vial_location: Union[
|
42
|
+
vial_location: Union[TenVialColumn, int]
|
43
43
|
method: Optional[str] = None
|
44
44
|
num_inj: Optional[int] = 1
|
45
45
|
inj_vol: Optional[int] = 2
|
@@ -37,17 +37,20 @@ class RegisterFlag(Enum):
|
|
37
37
|
SOLVENT_D_COMPOSITION = "PumpChannel4_CompositionPercentage"
|
38
38
|
FLOW = "Flow"
|
39
39
|
MAX_TIME = "StopTime_Time"
|
40
|
+
POST_TIME = "PostTime_Time" #TODO: check
|
40
41
|
COLUMN_OVEN_TEMP1 = "TemperatureControl_Temperature"
|
41
42
|
COLUMN_OVEN_TEMP2 = "TemperatureControl2_Temperature"
|
42
43
|
STOPTIME_MODE = "StopTime_Mode"
|
43
44
|
POSTIME_MODE = "PostTime_Mode"
|
44
45
|
TIME = "Time"
|
45
46
|
TIMETABLE_SOLVENT_B_COMPOSITION = "SolventCompositionPumpChannel2_Percentage"
|
47
|
+
TIMETABLE_FLOW = "FlowFlow"
|
46
48
|
|
47
49
|
# for Method Timetable
|
48
50
|
SOLVENT_COMPOSITION = "SolventComposition"
|
49
51
|
PRESSURE = "Pressure"
|
50
52
|
EXTERNAL_CONTACT = "ExternalContact"
|
53
|
+
FUNCTION = "Function"
|
51
54
|
|
52
55
|
|
53
56
|
# for Sequence
|
@@ -1,7 +1,43 @@
|
|
1
|
+
from dataclasses import dataclass
|
1
2
|
from enum import Enum
|
2
3
|
|
3
4
|
|
4
|
-
class
|
5
|
+
class Num(Enum):
|
6
|
+
ONE = 1
|
7
|
+
TWO = 2
|
8
|
+
THREE = 3
|
9
|
+
FOUR = 4
|
10
|
+
FIVE = 5
|
11
|
+
SIX = 6
|
12
|
+
SEVEN = 7
|
13
|
+
EIGHT = 8
|
14
|
+
NINE = 9
|
15
|
+
|
16
|
+
|
17
|
+
class Plate(Enum):
|
18
|
+
ONE = "1"
|
19
|
+
TWO = "2"
|
20
|
+
|
21
|
+
|
22
|
+
class Letter(Enum):
|
23
|
+
A = 8191
|
24
|
+
B = 8255
|
25
|
+
C = 8319
|
26
|
+
D = 8383
|
27
|
+
F = 8447
|
28
|
+
|
29
|
+
|
30
|
+
@dataclass
|
31
|
+
class FiftyFourVialPlate:
|
32
|
+
plate: Plate
|
33
|
+
letter: Letter
|
34
|
+
num: Num
|
35
|
+
|
36
|
+
def value(self) -> int:
|
37
|
+
return self.letter.value + self.num.value
|
38
|
+
|
39
|
+
|
40
|
+
class TenVialColumn(Enum):
|
5
41
|
ONE = 1
|
6
42
|
TWO = 2
|
7
43
|
THREE = 3
|
@@ -5,12 +5,12 @@ pychemstation/analysis/spec_utils.py,sha256=UOo9hJR3evJfmaohEEsyb7aq6X996ofuUfu-
|
|
5
5
|
pychemstation/analysis/utils.py,sha256=ISupAOb_yqA4_DZRK9v18UL-XjUQccAicIJKb1VMnGg,2055
|
6
6
|
pychemstation/control/__init__.py,sha256=4xTy8X-mkn_PPZKr7w9rnj1wZhtmTesbQptPhpYmKXs,64
|
7
7
|
pychemstation/control/comm.py,sha256=u44g1hTluQ0yUG93Un-QAshScoDpgYRrZfFTgweP5tY,7386
|
8
|
-
pychemstation/control/hplc.py,sha256=
|
8
|
+
pychemstation/control/hplc.py,sha256=5xC5q-hrAn5hKdz-ZwT_Dlas9LWLV27jZvhCKj7Lzg4,8761
|
9
9
|
pychemstation/control/controllers/__init__.py,sha256=di3ytLIK-35XC_THw4IjNaOtCUTe7GuEOFb-obmREw4,166
|
10
10
|
pychemstation/control/controllers/comm.py,sha256=IU4I_Q42VNCNUlVi93MxCmw2EBY9hiBDkU9FxubKg3c,7441
|
11
|
-
pychemstation/control/controllers/method.py,sha256=
|
12
|
-
pychemstation/control/controllers/sequence.py,sha256=
|
13
|
-
pychemstation/control/controllers/table_controller.py,sha256=
|
11
|
+
pychemstation/control/controllers/method.py,sha256=XUclB7lQ_SIkquR58MBmmi9drHIPEq9AR8VprTLenvI,15503
|
12
|
+
pychemstation/control/controllers/sequence.py,sha256=XMaYvbMRBdaZPdEEL12oAl5uUIDi-_fbPJUU-Uxtk8I,8297
|
13
|
+
pychemstation/control/controllers/table_controller.py,sha256=ItuNJ3aQqx73rviGVXs7vYaZKA9icPFreOUuUZupqB4,11029
|
14
14
|
pychemstation/control/table/__init__.py,sha256=RgMN4uIWHdNUHpGRBWdzmzAbk7XEKl6Y-qtqWCxzSZU,124
|
15
15
|
pychemstation/control/table/method.py,sha256=THVoGomSXff_CTU3eAYme0BYwkPzab5UgZKsiZ29QSk,12196
|
16
16
|
pychemstation/control/table/sequence.py,sha256=Eri52AnbE3BGthfrRSvYKYciquUzvHKo0lYUTySYYE8,10542
|
@@ -20,20 +20,20 @@ pychemstation/generated/dad_method.py,sha256=0W8Z5WDtF5jpIcudMqb7XrkTnR2EGg_QOCs
|
|
20
20
|
pychemstation/generated/pump_method.py,sha256=sUhE2Oo00nzVcoONtq3EMWsN4wLSryXbG8f3EeViWKg,12174
|
21
21
|
pychemstation/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
22
22
|
pychemstation/utils/chromatogram.py,sha256=-q3_hL9GTyi4C95os7IwAiOrkTM4EXIiigm-nW9pFmM,3221
|
23
|
-
pychemstation/utils/macro.py,sha256=
|
24
|
-
pychemstation/utils/method_types.py,sha256=
|
23
|
+
pychemstation/utils/macro.py,sha256=a6M6iK6c56Z75Opr2a-gsLKvMMpShu05DwcBYn5aTUs,2778
|
24
|
+
pychemstation/utils/method_types.py,sha256=SRpr61Ca57NzfYoDiaooeI5tw1ESgVj_2-MctGyuN60,1478
|
25
25
|
pychemstation/utils/parsing.py,sha256=bnFIsZZwFy9NKzVUf517yN-ogzQbm0hp_aho3KUD6Is,9317
|
26
|
-
pychemstation/utils/sequence_types.py,sha256=
|
27
|
-
pychemstation/utils/table_types.py,sha256=
|
28
|
-
pychemstation/utils/tray_types.py,sha256=
|
26
|
+
pychemstation/utils/sequence_types.py,sha256=OhbmBUS7XQOKHC8YLjgbEVdpjriEc1bORkwB5ZV43oA,1063
|
27
|
+
pychemstation/utils/table_types.py,sha256=HVE_tuM2TUED843iXvZqtONt8Eeolm6B5eciq60ZjR8,2521
|
28
|
+
pychemstation/utils/tray_types.py,sha256=NzeH1IYI-k6u-2QrZshhx-lNlvOmGoOElbZ0fspT-38,654
|
29
29
|
tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
30
|
-
tests/constants.py,sha256=
|
31
|
-
tests/test_comb.py,sha256=
|
32
|
-
tests/test_comm.py,sha256=
|
33
|
-
tests/test_method.py,sha256=
|
34
|
-
tests/test_sequence.py,sha256=
|
35
|
-
pychemstation-0.5.
|
36
|
-
pychemstation-0.5.
|
37
|
-
pychemstation-0.5.
|
38
|
-
pychemstation-0.5.
|
39
|
-
pychemstation-0.5.
|
30
|
+
tests/constants.py,sha256=iU6knsNpQGnBfGcC8VAj5SrCDcHD3jBZLhQdF6UUwY4,2452
|
31
|
+
tests/test_comb.py,sha256=EDE1Ve0A_EK4qro9imZsrD0xXrQN8hAowiOWPFtw3dM,5515
|
32
|
+
tests/test_comm.py,sha256=EYOpVXzEMQLGhhKYDPO-KaLcJdPSMPTD9Y4jSI0yVQY,2516
|
33
|
+
tests/test_method.py,sha256=r1Q1irqiVzs31QuTYLX3u_A0FpX8rIAQ1L4WOk9tLbk,2473
|
34
|
+
tests/test_sequence.py,sha256=Nz2iqp1cJgw6kcQvnwSkfBmhxpOH62PoEu6o_5rO-PY,4929
|
35
|
+
pychemstation-0.5.10.dist-info/LICENSE,sha256=9bdF75gIf1MecZ7oymqWgJREVz7McXPG-mjqrTmzzD8,18658
|
36
|
+
pychemstation-0.5.10.dist-info/METADATA,sha256=tcPTswg-NhMQlf7iDC1iYmUlKCta5QSSVFxoUVP8Wgc,4308
|
37
|
+
pychemstation-0.5.10.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
38
|
+
pychemstation-0.5.10.dist-info/top_level.txt,sha256=zXfKu_4nYWwPHo3OsuhshMNC3SPkcoTGCyODjURaghY,20
|
39
|
+
pychemstation-0.5.10.dist-info/RECORD,,
|
tests/constants.py
CHANGED
@@ -39,24 +39,24 @@ def room(num: int):
|
|
39
39
|
def gen_rand_method():
|
40
40
|
org_modifier = int(random.random() * 10)
|
41
41
|
max_run_time = int(random.random() * 10)
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
42
|
+
post_run_time = int(random.random() * 10)
|
43
|
+
flow = float(random.random() * 10) / 10
|
44
|
+
flow_1 = float(random.random() * 10) / 10
|
45
|
+
flow_2 = float(random.random() * 10) / 10
|
46
|
+
return MethodDetails(name=DEFAULT_METHOD,
|
47
|
+
timetable=[TimeTableEntry(start_time=0.10,
|
48
|
+
organic_modifer=org_modifier,
|
49
|
+
flow=flow_1),
|
50
|
+
TimeTableEntry(start_time=1,
|
51
|
+
organic_modifer=100 - int(random.random() * 10),
|
52
|
+
flow=flow_2)],
|
53
|
+
stop_time=max_run_time,
|
54
|
+
post_time=post_run_time,
|
55
|
+
params=HPLCMethodParams(organic_modifier=org_modifier, flow=flow))
|
56
56
|
|
57
57
|
|
58
58
|
seq_entry = SequenceEntry(
|
59
|
-
vial_location=
|
59
|
+
vial_location=TenVialColumn.ONE,
|
60
60
|
method=DEFAULT_METHOD,
|
61
61
|
num_inj=int(random.random() * 10),
|
62
62
|
inj_vol=int(random.random() * 10),
|
tests/test_comb.py
CHANGED
@@ -24,17 +24,15 @@ class TestCombinations(unittest.TestCase):
|
|
24
24
|
def test_run_method_after_update(self):
|
25
25
|
try:
|
26
26
|
self.hplc_controller.method_controller.switch(DEFAULT_METHOD)
|
27
|
-
rand_method =
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
flow=0.65)],
|
37
|
-
name=DEFAULT_METHOD)
|
27
|
+
rand_method = MethodDetails(
|
28
|
+
params=HPLCMethodParams(organic_modifier=5,
|
29
|
+
flow=0.65),
|
30
|
+
timetable=[TimeTableEntry(start_time=3.5,
|
31
|
+
organic_modifer=100,
|
32
|
+
flow=0.65)],
|
33
|
+
name=DEFAULT_METHOD,
|
34
|
+
stop_time=10,
|
35
|
+
post_time=9)
|
38
36
|
self.hplc_controller.edit_method(rand_method, save=True)
|
39
37
|
if run_too:
|
40
38
|
self.hplc_controller.run_method(experiment_name="changed_method")
|
@@ -48,7 +46,7 @@ class TestCombinations(unittest.TestCase):
|
|
48
46
|
self.hplc_controller.switch_sequence(sequence_name=DEFAULT_SEQUENCE)
|
49
47
|
seq_table = self.hplc_controller.load_sequence()
|
50
48
|
seq_table.rows.append(SequenceEntry(
|
51
|
-
vial_location=
|
49
|
+
vial_location=TenVialColumn.ONE,
|
52
50
|
method=DEFAULT_METHOD,
|
53
51
|
num_inj=3,
|
54
52
|
inj_vol=4,
|
@@ -56,7 +54,7 @@ class TestCombinations(unittest.TestCase):
|
|
56
54
|
sample_type=SampleType.SAMPLE,
|
57
55
|
))
|
58
56
|
seq_table.rows[0] = SequenceEntry(
|
59
|
-
vial_location=
|
57
|
+
vial_location=TenVialColumn.ONE,
|
60
58
|
method=DEFAULT_METHOD,
|
61
59
|
num_inj=3,
|
62
60
|
inj_vol=4,
|
@@ -85,43 +83,38 @@ class TestCombinations(unittest.TestCase):
|
|
85
83
|
def test_update_method_update_seq_table_run(self):
|
86
84
|
try:
|
87
85
|
self.hplc_controller.method_controller.switch(DEFAULT_METHOD)
|
88
|
-
rand_method =
|
89
|
-
|
86
|
+
rand_method = MethodDetails(
|
87
|
+
name=DEFAULT_METHOD,
|
88
|
+
params=HPLCMethodParams(
|
90
89
|
organic_modifier=5,
|
91
|
-
flow=0.65,
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
name=DEFAULT_METHOD)
|
90
|
+
flow=0.65),
|
91
|
+
timetable=[TimeTableEntry(
|
92
|
+
start_time=0.50,
|
93
|
+
organic_modifer=99,
|
94
|
+
flow=0.34)],
|
95
|
+
stop_time=10,
|
96
|
+
post_time=5)
|
99
97
|
self.hplc_controller.edit_method(rand_method, save=True)
|
100
98
|
|
101
99
|
self.hplc_controller.switch_sequence(sequence_name=DEFAULT_SEQUENCE)
|
102
100
|
seq_table = SequenceTable(
|
103
101
|
name=DEFAULT_SEQUENCE,
|
104
|
-
rows=[
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
num_inj=1,
|
121
|
-
sample_type=SampleType.SAMPLE
|
122
|
-
),
|
123
|
-
]
|
124
|
-
)
|
102
|
+
rows=[SequenceEntry(
|
103
|
+
vial_location=8320,
|
104
|
+
sample_name="WM-01-001_Cr-Org",
|
105
|
+
method=DEFAULT_METHOD,
|
106
|
+
inj_source=InjectionSource.HIP_ALS,
|
107
|
+
inj_vol=2,
|
108
|
+
num_inj=1,
|
109
|
+
sample_type=SampleType.SAMPLE
|
110
|
+
), SequenceEntry(
|
111
|
+
vial_location=8448,
|
112
|
+
sample_name="WM-01-001_Cr-Aq",
|
113
|
+
method=DEFAULT_METHOD,
|
114
|
+
inj_source=InjectionSource.HIP_ALS,
|
115
|
+
inj_vol=2,
|
116
|
+
num_inj=1,
|
117
|
+
sample_type=SampleType.SAMPLE)])
|
125
118
|
|
126
119
|
self.hplc_controller.edit_sequence(seq_table)
|
127
120
|
if run_too:
|
tests/test_comm.py
CHANGED
@@ -42,7 +42,7 @@ class TestComm(unittest.TestCase):
|
|
42
42
|
self.hplc_controller.send("TestNum = 0")
|
43
43
|
self.hplc_controller.send("Print TestNum")
|
44
44
|
self.hplc_controller.send("response_num = TestNum")
|
45
|
-
self.hplc_controller.send("Print
|
45
|
+
self.hplc_controller.send("Print response_num")
|
46
46
|
except Exception as e:
|
47
47
|
self.fail(f"Should not throw error: {e}")
|
48
48
|
|
@@ -63,16 +63,3 @@ class TestComm(unittest.TestCase):
|
|
63
63
|
except Exception as e:
|
64
64
|
self.fail(f"Should not throw error: {e}")
|
65
65
|
|
66
|
-
def test_pump_lamp(self):
|
67
|
-
pump_lamp = [
|
68
|
-
("response", self.hplc_controller.lamp_on),
|
69
|
-
("response", self.hplc_controller.lamp_off),
|
70
|
-
("response", self.hplc_controller.pump_on),
|
71
|
-
("response", self.hplc_controller.pump_off),
|
72
|
-
]
|
73
|
-
|
74
|
-
for operation in pump_lamp:
|
75
|
-
try:
|
76
|
-
operation[1]()
|
77
|
-
except Exception as e:
|
78
|
-
self.fail(f"Failed due to: {e}")
|
tests/test_method.py
CHANGED
@@ -40,12 +40,12 @@ class TestMethod(unittest.TestCase):
|
|
40
40
|
try:
|
41
41
|
self.hplc_controller.edit_method(new_method)
|
42
42
|
loaded_method = self.hplc_controller.load_method()
|
43
|
-
self.assertEqual(new_method.
|
44
|
-
loaded_method.
|
45
|
-
self.assertEqual(new_method.
|
46
|
-
loaded_method.
|
47
|
-
self.assertEqual(new_method.
|
48
|
-
loaded_method.
|
43
|
+
self.assertEqual(new_method.params.organic_modifier,
|
44
|
+
loaded_method.params.organic_modifier)
|
45
|
+
self.assertEqual(new_method.timetable[0].organic_modifer,
|
46
|
+
loaded_method.timetable[0].organic_modifer)
|
47
|
+
self.assertEqual(round(new_method.params.flow, 2),
|
48
|
+
round(loaded_method.params.flow, 2))
|
49
49
|
except Exception as e:
|
50
50
|
self.fail(f"Should have not failed: {e}")
|
51
51
|
|
@@ -58,4 +58,4 @@ class TestMethod(unittest.TestCase):
|
|
58
58
|
|
59
59
|
|
60
60
|
if __name__ == '__main__':
|
61
|
-
unittest.main()
|
61
|
+
unittest.main()
|
tests/test_sequence.py
CHANGED
@@ -29,7 +29,7 @@ class TestSequence(unittest.TestCase):
|
|
29
29
|
self.hplc_controller.switch_sequence(sequence_name=DEFAULT_SEQUENCE)
|
30
30
|
try:
|
31
31
|
self.hplc_controller.edit_sequence_row(SequenceEntry(
|
32
|
-
vial_location=
|
32
|
+
vial_location=TenVialColumn.TEN,
|
33
33
|
method=DEFAULT_METHOD,
|
34
34
|
num_inj=3,
|
35
35
|
inj_vol=4,
|
@@ -47,7 +47,7 @@ class TestSequence(unittest.TestCase):
|
|
47
47
|
name=DEFAULT_SEQUENCE,
|
48
48
|
rows=[
|
49
49
|
SequenceEntry(
|
50
|
-
vial_location=
|
50
|
+
vial_location=TenVialColumn.ONE,
|
51
51
|
method=DEFAULT_METHOD,
|
52
52
|
num_inj=3,
|
53
53
|
inj_vol=4,
|
@@ -56,7 +56,7 @@ class TestSequence(unittest.TestCase):
|
|
56
56
|
inj_source=InjectionSource.HIP_ALS
|
57
57
|
),
|
58
58
|
SequenceEntry(
|
59
|
-
vial_location=
|
59
|
+
vial_location=TenVialColumn.TWO,
|
60
60
|
method=DEFAULT_METHOD,
|
61
61
|
num_inj=3,
|
62
62
|
inj_vol=4,
|
@@ -65,7 +65,7 @@ class TestSequence(unittest.TestCase):
|
|
65
65
|
inj_source=InjectionSource.HIP_ALS
|
66
66
|
),
|
67
67
|
SequenceEntry(
|
68
|
-
vial_location=
|
68
|
+
vial_location=TenVialColumn.TEN,
|
69
69
|
method=DEFAULT_METHOD,
|
70
70
|
num_inj=3,
|
71
71
|
inj_vol=4,
|
@@ -74,7 +74,7 @@ class TestSequence(unittest.TestCase):
|
|
74
74
|
inj_source=InjectionSource.HIP_ALS
|
75
75
|
),
|
76
76
|
SequenceEntry(
|
77
|
-
vial_location=
|
77
|
+
vial_location=TenVialColumn.THREE,
|
78
78
|
method=DEFAULT_METHOD,
|
79
79
|
num_inj=3,
|
80
80
|
inj_vol=4,
|
@@ -95,7 +95,7 @@ class TestSequence(unittest.TestCase):
|
|
95
95
|
name=DEFAULT_SEQUENCE,
|
96
96
|
rows=[
|
97
97
|
SequenceEntry(
|
98
|
-
vial_location=
|
98
|
+
vial_location=TenVialColumn.TEN,
|
99
99
|
method=DEFAULT_METHOD,
|
100
100
|
num_inj=3,
|
101
101
|
inj_vol=4,
|
@@ -104,7 +104,7 @@ class TestSequence(unittest.TestCase):
|
|
104
104
|
inj_source=InjectionSource.HIP_ALS
|
105
105
|
),
|
106
106
|
SequenceEntry(
|
107
|
-
vial_location=
|
107
|
+
vial_location=TenVialColumn.THREE,
|
108
108
|
method=DEFAULT_METHOD,
|
109
109
|
num_inj=3,
|
110
110
|
inj_vol=4,
|
File without changes
|
File without changes
|
File without changes
|