pychemstation 0.10.3__py3-none-any.whl → 0.10.5__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/__init__.py +1 -1
- pychemstation/analysis/__init__.py +1 -6
- pychemstation/analysis/base_spectrum.py +7 -7
- pychemstation/{utils → analysis}/chromatogram.py +24 -4
- pychemstation/analysis/process_report.py +189 -90
- pychemstation/control/__init__.py +5 -2
- pychemstation/control/controllers/__init__.py +2 -7
- pychemstation/control/controllers/comm.py +56 -32
- pychemstation/control/controllers/devices/device.py +59 -24
- pychemstation/control/controllers/devices/injector.py +33 -10
- pychemstation/control/controllers/tables/__init__.py +4 -0
- pychemstation/control/controllers/tables/method.py +241 -151
- pychemstation/control/controllers/tables/sequence.py +226 -107
- pychemstation/control/controllers/tables/table.py +216 -132
- pychemstation/control/hplc.py +89 -75
- pychemstation/generated/__init__.py +0 -2
- pychemstation/generated/pump_method.py +15 -19
- pychemstation/utils/injector_types.py +1 -1
- pychemstation/utils/macro.py +11 -10
- pychemstation/utils/method_types.py +2 -1
- pychemstation/utils/parsing.py +0 -11
- pychemstation/utils/sequence_types.py +2 -3
- pychemstation/utils/spec_utils.py +2 -3
- pychemstation/utils/table_types.py +10 -9
- pychemstation/utils/tray_types.py +45 -36
- {pychemstation-0.10.3.dist-info → pychemstation-0.10.5.dist-info}/METADATA +5 -4
- pychemstation-0.10.5.dist-info/RECORD +36 -0
- pychemstation/control/controllers/tables/ms.py +0 -21
- pychemstation-0.10.3.dist-info/RECORD +0 -37
- {pychemstation-0.10.3.dist-info → pychemstation-0.10.5.dist-info}/WHEEL +0 -0
- {pychemstation-0.10.3.dist-info → pychemstation-0.10.5.dist-info}/licenses/LICENSE +0 -0
@@ -1,15 +1,15 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
1
3
|
import os
|
2
4
|
import time
|
3
5
|
import warnings
|
4
|
-
from typing import
|
6
|
+
from typing import List, Optional, Union, Dict
|
5
7
|
|
6
8
|
from result import Err, Ok, Result
|
7
|
-
from xsdata.formats.dataclass.parsers import XmlParser
|
8
9
|
|
9
10
|
from ....analysis.process_report import AgilentReport, ReportType
|
10
11
|
from ....control.controllers import CommunicationController
|
11
|
-
from
|
12
|
-
from ....utils.chromatogram import (
|
12
|
+
from pychemstation.analysis.chromatogram import (
|
13
13
|
TIME_FORMAT,
|
14
14
|
AgilentChannelChromatogramData,
|
15
15
|
AgilentHPLCChromatogram,
|
@@ -22,7 +22,7 @@ from ....utils.method_types import (
|
|
22
22
|
PType,
|
23
23
|
TimeTableEntry,
|
24
24
|
)
|
25
|
-
from ....utils.table_types import RegisterFlag,
|
25
|
+
from ....utils.table_types import RegisterFlag, Table, TableOperation, T
|
26
26
|
from ..devices.injector import InjectorController
|
27
27
|
from .table import TableController
|
28
28
|
|
@@ -32,15 +32,24 @@ class MethodController(TableController):
|
|
32
32
|
Class containing method related logic
|
33
33
|
"""
|
34
34
|
|
35
|
-
def __init__(
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
35
|
+
def __init__(
|
36
|
+
self,
|
37
|
+
controller: CommunicationController,
|
38
|
+
src: str,
|
39
|
+
data_dirs: List[str],
|
40
|
+
table: Table,
|
41
|
+
offline: bool,
|
42
|
+
injector_controller: InjectorController,
|
43
|
+
):
|
41
44
|
self.injector_controller = injector_controller
|
42
45
|
self.data_files: List[str] = []
|
43
|
-
super().__init__(
|
46
|
+
super().__init__(
|
47
|
+
controller=controller,
|
48
|
+
src=src,
|
49
|
+
data_dirs=data_dirs,
|
50
|
+
table=table,
|
51
|
+
offline=offline,
|
52
|
+
)
|
44
53
|
|
45
54
|
def check(self) -> str:
|
46
55
|
time.sleep(2)
|
@@ -52,19 +61,22 @@ class MethodController(TableController):
|
|
52
61
|
return "ERROR"
|
53
62
|
|
54
63
|
def get_method_params(self) -> HPLCMethodParams:
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
64
|
+
if self.controller:
|
65
|
+
return HPLCMethodParams(
|
66
|
+
organic_modifier=self.controller.get_num_val(
|
67
|
+
cmd=TableOperation.GET_OBJ_HDR_VAL.value.format(
|
68
|
+
register=self.table_locator.register,
|
69
|
+
register_flag=RegisterFlag.SOLVENT_B_COMPOSITION,
|
70
|
+
)
|
71
|
+
),
|
72
|
+
flow=self.controller.get_num_val(
|
73
|
+
cmd=TableOperation.GET_OBJ_HDR_VAL.value.format(
|
74
|
+
register=self.table_locator.register,
|
75
|
+
register_flag=RegisterFlag.FLOW,
|
76
|
+
)
|
77
|
+
),
|
59
78
|
)
|
60
|
-
)
|
61
|
-
flow=self.controller.get_num_val(
|
62
|
-
cmd=TableOperation.GET_OBJ_HDR_VAL.value.format(
|
63
|
-
register=self.table_locator.register,
|
64
|
-
register_flag=RegisterFlag.FLOW
|
65
|
-
)
|
66
|
-
),
|
67
|
-
)
|
79
|
+
raise ValueError("Communication controller is offline!")
|
68
80
|
|
69
81
|
def get_row(self, row: int) -> TimeTableEntry:
|
70
82
|
flow = None
|
@@ -79,19 +91,26 @@ class MethodController(TableController):
|
|
79
91
|
except RuntimeError:
|
80
92
|
pass
|
81
93
|
|
82
|
-
|
83
|
-
|
84
|
-
|
94
|
+
if om is None and flow is None:
|
95
|
+
raise ValueError("Both flow and organic modifier is None")
|
96
|
+
|
97
|
+
return TimeTableEntry(
|
98
|
+
start_time=self.get_num(row, RegisterFlag.TIME),
|
99
|
+
organic_modifer=om,
|
100
|
+
flow=flow,
|
101
|
+
)
|
85
102
|
|
86
103
|
def get_timetable(self, rows: int):
|
87
104
|
uncoalesced_timetable_rows = [self.get_row(r + 1) for r in range(rows)]
|
88
|
-
timetable_rows = {}
|
105
|
+
timetable_rows: Dict[str, TimeTableEntry] = {}
|
89
106
|
for row in uncoalesced_timetable_rows:
|
90
107
|
time_key = str(row.start_time)
|
91
108
|
if time_key not in timetable_rows.keys():
|
92
|
-
timetable_rows[time_key] = TimeTableEntry(
|
93
|
-
|
94
|
-
|
109
|
+
timetable_rows[time_key] = TimeTableEntry(
|
110
|
+
start_time=row.start_time,
|
111
|
+
flow=row.flow,
|
112
|
+
organic_modifer=row.organic_modifer,
|
113
|
+
)
|
95
114
|
else:
|
96
115
|
if row.flow:
|
97
116
|
timetable_rows[time_key].flow = row.flow
|
@@ -109,11 +128,13 @@ class MethodController(TableController):
|
|
109
128
|
params = self.get_method_params()
|
110
129
|
stop_time = self.get_stop_time()
|
111
130
|
post_time = self.get_post_time()
|
112
|
-
self.table_state = MethodDetails(
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
131
|
+
self.table_state = MethodDetails(
|
132
|
+
name=method_name,
|
133
|
+
timetable=timetable_rows,
|
134
|
+
stop_time=stop_time,
|
135
|
+
post_time=post_time,
|
136
|
+
params=params,
|
137
|
+
)
|
117
138
|
return self.table_state
|
118
139
|
else:
|
119
140
|
raise RuntimeError(rows.err_value)
|
@@ -125,16 +146,24 @@ class MethodController(TableController):
|
|
125
146
|
return method_name
|
126
147
|
|
127
148
|
def get_post_time(self) -> Union[int, float]:
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
149
|
+
if self.controller:
|
150
|
+
return self.controller.get_num_val(
|
151
|
+
cmd=TableOperation.GET_OBJ_HDR_VAL.value.format(
|
152
|
+
register=self.table_locator.register,
|
153
|
+
register_flag=RegisterFlag.POST_TIME,
|
154
|
+
)
|
155
|
+
)
|
156
|
+
raise ValueError("Communication controller is not online!")
|
132
157
|
|
133
158
|
def get_stop_time(self) -> Union[int, float]:
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
159
|
+
if self.controller:
|
160
|
+
return self.controller.get_num_val(
|
161
|
+
cmd=TableOperation.GET_OBJ_HDR_VAL.value.format(
|
162
|
+
register=self.table_locator.register,
|
163
|
+
register_flag=RegisterFlag.MAX_TIME,
|
164
|
+
)
|
165
|
+
)
|
166
|
+
raise ValueError("Communication controller is not online!")
|
138
167
|
|
139
168
|
def get_total_runtime(self) -> Union[int, float]:
|
140
169
|
"""Returns total method runtime in minutes."""
|
@@ -163,7 +192,11 @@ class MethodController(TableController):
|
|
163
192
|
:raise AssertionError: The desired method is not selected. Try again.
|
164
193
|
"""
|
165
194
|
method_dir = self.src if not alt_method_dir else alt_method_dir
|
166
|
-
self.send(
|
195
|
+
self.send(
|
196
|
+
Command.SWITCH_METHOD_CMD_SPECIFIC.value.format(
|
197
|
+
method_dir=method_dir, method_name=method_name
|
198
|
+
)
|
199
|
+
)
|
167
200
|
|
168
201
|
time.sleep(2)
|
169
202
|
self.send(Command.GET_METHOD_CMD)
|
@@ -174,50 +207,6 @@ class MethodController(TableController):
|
|
174
207
|
assert parsed_response == f"{method_name}.M", "Switching Methods failed."
|
175
208
|
self.table_state = None
|
176
209
|
|
177
|
-
def load_from_disk(self, method_name: str) -> MethodDetails:
|
178
|
-
"""
|
179
|
-
Retrieve method details of an existing method. Don't need to append ".M" to the end. This assumes the
|
180
|
-
organic modifier is in Channel B and that Channel A contains the aq layer. Additionally, assumes
|
181
|
-
only two solvents are being used.
|
182
|
-
|
183
|
-
:param method_name: name of method to load details of
|
184
|
-
:raises FileNotFoundError: Method does not exist
|
185
|
-
:return: method details
|
186
|
-
"""
|
187
|
-
warnings.warn("This method is not actively maintained.")
|
188
|
-
method_folder = f"{method_name}.M"
|
189
|
-
method_path = os.path.join(self.src, method_folder, "AgilentPumpDriver1.RapidControl.MethodXML.xml")
|
190
|
-
dad_path = os.path.join(self.src, method_folder, "Agilent1200erDadDriver1.RapidControl.MethodXML.xml")
|
191
|
-
|
192
|
-
if os.path.exists(os.path.join(self.src, f"{method_name}.M")):
|
193
|
-
parser = XmlParser()
|
194
|
-
method = parser.parse(method_path, PumpMethod)
|
195
|
-
dad = parser.parse(dad_path, DadMethod)
|
196
|
-
|
197
|
-
organic_modifier: Optional[SolventElement] = None
|
198
|
-
aq_modifier: Optional[SolventElement] = None
|
199
|
-
|
200
|
-
if len(method.solvent_composition.solvent_element) == 2:
|
201
|
-
for solvent in method.solvent_composition.solvent_element:
|
202
|
-
if solvent.channel == "Channel_A":
|
203
|
-
aq_modifier = solvent
|
204
|
-
elif solvent.channel == "Channel_B":
|
205
|
-
organic_modifier = solvent
|
206
|
-
|
207
|
-
self.table_state = MethodDetails(name=method_name,
|
208
|
-
params=HPLCMethodParams(organic_modifier=organic_modifier.percentage,
|
209
|
-
flow=method.flow),
|
210
|
-
stop_time=method.stop_time.stop_time_value,
|
211
|
-
post_time=method.post_time.post_time_value,
|
212
|
-
timetable=[TimeTableEntry(start_time=tte.time,
|
213
|
-
organic_modifer=tte.percent_b,
|
214
|
-
flow=method.flow
|
215
|
-
) for tte in method.timetable.timetable_entry],
|
216
|
-
dad_wavelengthes=dad.signals.signal)
|
217
|
-
return self.table_state
|
218
|
-
else:
|
219
|
-
raise FileNotFoundError
|
220
|
-
|
221
210
|
def edit(self, updated_method: MethodDetails, save: bool):
|
222
211
|
"""Updated the currently loaded method in ChemStation with provided values.
|
223
212
|
|
@@ -225,43 +214,90 @@ class MethodController(TableController):
|
|
225
214
|
:param save: if false only modifies the method, otherwise saves to disk
|
226
215
|
"""
|
227
216
|
self.table_state = updated_method
|
228
|
-
initial_organic_modifier: Param = Param(val=updated_method.params.organic_modifier,
|
229
|
-
chemstation_key=RegisterFlag.SOLVENT_B_COMPOSITION,
|
230
|
-
ptype=PType.NUM)
|
231
|
-
max_time: Param = Param(val=updated_method.stop_time,
|
232
|
-
chemstation_key=RegisterFlag.MAX_TIME,
|
233
|
-
ptype=PType.NUM)
|
234
|
-
post_time: Param = Param(val=updated_method.post_time,
|
235
|
-
chemstation_key=RegisterFlag.POST_TIME,
|
236
|
-
ptype=PType.NUM)
|
237
|
-
flow: Param = Param(val=updated_method.params.flow,
|
238
|
-
chemstation_key=RegisterFlag.FLOW,
|
239
|
-
ptype=PType.NUM)
|
240
|
-
|
241
217
|
# Method settings required for all runs
|
242
|
-
self.update_method_params(
|
243
|
-
|
218
|
+
self.update_method_params(
|
219
|
+
new_flow=updated_method.params.flow,
|
220
|
+
new_initial_om=updated_method.params.organic_modifier,
|
221
|
+
new_stop_time=updated_method.stop_time,
|
222
|
+
new_post_time=updated_method.post_time,
|
223
|
+
)
|
224
|
+
self.edit_method_timetable(updated_method.timetable)
|
244
225
|
|
245
226
|
if save:
|
246
|
-
self.send(
|
247
|
-
|
248
|
-
|
227
|
+
self.send(
|
228
|
+
Command.SAVE_METHOD_CMD.value.format(
|
229
|
+
commit_msg=f"saved method at {str(time.time())}"
|
230
|
+
)
|
231
|
+
)
|
249
232
|
|
250
|
-
def
|
251
|
-
|
233
|
+
def edit_initial_om(self, new_om: Union[int, float]):
|
234
|
+
initial_organic_modifier: Param = Param(
|
235
|
+
val=new_om,
|
236
|
+
chemstation_key=RegisterFlag.SOLVENT_B_COMPOSITION,
|
237
|
+
ptype=PType.NUM,
|
238
|
+
)
|
252
239
|
self._update_param(initial_organic_modifier)
|
240
|
+
|
241
|
+
def edit_flow(self, new_flow: Union[int, float]):
|
242
|
+
flow: Param = Param(
|
243
|
+
val=new_flow, chemstation_key=RegisterFlag.FLOW, ptype=PType.NUM
|
244
|
+
)
|
253
245
|
self._update_param(flow)
|
254
|
-
|
255
|
-
|
256
|
-
|
246
|
+
|
247
|
+
def edit_stop_time(self, new_stop_time: Union[int, float]):
|
248
|
+
stop_time: Param = Param(
|
249
|
+
val=new_stop_time,
|
250
|
+
chemstation_key=RegisterFlag.MAX_TIME,
|
251
|
+
ptype=PType.NUM,
|
252
|
+
)
|
253
|
+
self._update_param(
|
254
|
+
Param(
|
255
|
+
val="Set", chemstation_key=RegisterFlag.STOPTIME_MODE, ptype=PType.STR
|
256
|
+
)
|
257
|
+
)
|
258
|
+
self._update_param(stop_time)
|
259
|
+
|
260
|
+
def edit_post_time(self, new_post_time: Union[int, float]):
|
261
|
+
post_time: Param = Param(
|
262
|
+
val=new_post_time,
|
263
|
+
chemstation_key=RegisterFlag.POST_TIME,
|
264
|
+
ptype=PType.NUM,
|
265
|
+
)
|
266
|
+
self._update_param(
|
267
|
+
Param(val="Set", chemstation_key=RegisterFlag.POSTIME_MODE, ptype=PType.STR)
|
268
|
+
)
|
269
|
+
self._update_param(post_time)
|
270
|
+
|
271
|
+
def update_method_params(
|
272
|
+
self,
|
273
|
+
new_flow: Union[int, float],
|
274
|
+
new_initial_om: Union[int, float],
|
275
|
+
new_stop_time: Union[int, float] | None,
|
276
|
+
new_post_time: Union[int, float] | None,
|
277
|
+
):
|
278
|
+
self.delete_table()
|
279
|
+
self.edit_initial_om(new_initial_om)
|
280
|
+
self.edit_flow(new_flow)
|
281
|
+
if new_stop_time:
|
282
|
+
self.edit_stop_time(new_stop_time)
|
257
283
|
else:
|
258
|
-
self._update_param(
|
259
|
-
|
260
|
-
|
261
|
-
|
284
|
+
self._update_param(
|
285
|
+
Param(
|
286
|
+
val="Off",
|
287
|
+
chemstation_key=RegisterFlag.STOPTIME_MODE,
|
288
|
+
ptype=PType.STR,
|
289
|
+
)
|
290
|
+
)
|
291
|
+
if new_post_time:
|
292
|
+
self.edit_post_time(new_post_time)
|
262
293
|
else:
|
263
|
-
self._update_param(
|
264
|
-
|
294
|
+
self._update_param(
|
295
|
+
Param(
|
296
|
+
val="Off",
|
297
|
+
chemstation_key=RegisterFlag.POSTIME_MODE,
|
298
|
+
ptype=PType.STR,
|
299
|
+
)
|
300
|
+
)
|
265
301
|
|
266
302
|
def _update_param(self, method_param: Param):
|
267
303
|
"""Change a method parameter, changes what is visibly seen in Chemstation GUI.
|
@@ -270,34 +306,55 @@ class MethodController(TableController):
|
|
270
306
|
:param method_param: a parameter to update for currently loaded method.
|
271
307
|
"""
|
272
308
|
register = self.table_locator.register
|
273
|
-
setting_command =
|
309
|
+
setting_command = (
|
310
|
+
TableOperation.UPDATE_OBJ_HDR_VAL
|
311
|
+
if method_param.ptype == PType.NUM
|
312
|
+
else TableOperation.UPDATE_OBJ_HDR_TEXT
|
313
|
+
)
|
274
314
|
if isinstance(method_param.chemstation_key, list):
|
275
315
|
for register_flag in method_param.chemstation_key:
|
276
|
-
self.send(
|
277
|
-
|
278
|
-
|
316
|
+
self.send(
|
317
|
+
setting_command.value.format(
|
318
|
+
register=register,
|
319
|
+
register_flag=register_flag,
|
320
|
+
val=method_param.val,
|
321
|
+
)
|
322
|
+
)
|
279
323
|
else:
|
280
|
-
self.send(
|
281
|
-
|
282
|
-
|
324
|
+
self.send(
|
325
|
+
setting_command.value.format(
|
326
|
+
register=register,
|
327
|
+
register_flag=method_param.chemstation_key,
|
328
|
+
val=method_param.val,
|
329
|
+
)
|
330
|
+
)
|
283
331
|
time.sleep(2)
|
332
|
+
self.download()
|
284
333
|
|
285
334
|
def download(self):
|
286
|
-
self.send(
|
335
|
+
self.send("Sleep 1")
|
287
336
|
self.sleepy_send("DownloadRCMethod PMP1")
|
288
|
-
self.send(
|
337
|
+
self.send("Sleep 1")
|
289
338
|
|
290
|
-
def
|
339
|
+
def _edit_row(self, row: TimeTableEntry, first_row: bool = False):
|
291
340
|
if first_row:
|
292
341
|
if row.organic_modifer:
|
293
342
|
self.add_row()
|
294
|
-
self.add_new_col_text(
|
343
|
+
self.add_new_col_text(
|
344
|
+
col_name=RegisterFlag.FUNCTION,
|
345
|
+
val=RegisterFlag.SOLVENT_COMPOSITION.value,
|
346
|
+
)
|
295
347
|
self.add_new_col_num(col_name=RegisterFlag.TIME, val=row.start_time)
|
296
|
-
self.add_new_col_num(
|
348
|
+
self.add_new_col_num(
|
349
|
+
col_name=RegisterFlag.TIMETABLE_SOLVENT_B_COMPOSITION,
|
350
|
+
val=row.organic_modifer,
|
351
|
+
)
|
297
352
|
if row.flow:
|
298
353
|
self.add_row()
|
299
354
|
self.get_num_rows()
|
300
|
-
self._edit_row_text(
|
355
|
+
self._edit_row_text(
|
356
|
+
col_name=RegisterFlag.FUNCTION, val=RegisterFlag.FLOW.value
|
357
|
+
)
|
301
358
|
self.add_new_col_num(col_name=RegisterFlag.TIMETABLE_FLOW, val=row.flow)
|
302
359
|
self._edit_row_num(col_name=RegisterFlag.TIMETABLE_FLOW, val=row.flow)
|
303
360
|
self.download()
|
@@ -305,19 +362,27 @@ class MethodController(TableController):
|
|
305
362
|
if row.organic_modifer:
|
306
363
|
self.add_row()
|
307
364
|
self.get_num_rows()
|
308
|
-
self._edit_row_text(
|
365
|
+
self._edit_row_text(
|
366
|
+
col_name=RegisterFlag.FUNCTION,
|
367
|
+
val=RegisterFlag.SOLVENT_COMPOSITION.value,
|
368
|
+
)
|
309
369
|
self._edit_row_num(col_name=RegisterFlag.TIME, val=row.start_time)
|
310
|
-
self._edit_row_num(
|
370
|
+
self._edit_row_num(
|
371
|
+
col_name=RegisterFlag.TIMETABLE_SOLVENT_B_COMPOSITION,
|
372
|
+
val=row.organic_modifer,
|
373
|
+
)
|
311
374
|
self.download()
|
312
375
|
if row.flow:
|
313
376
|
self.add_row()
|
314
377
|
self.get_num_rows()
|
315
|
-
self._edit_row_text(
|
378
|
+
self._edit_row_text(
|
379
|
+
col_name=RegisterFlag.FUNCTION, val=RegisterFlag.FLOW.value
|
380
|
+
)
|
316
381
|
self._edit_row_num(col_name=RegisterFlag.TIMETABLE_FLOW, val=row.flow)
|
317
382
|
self._edit_row_num(col_name=RegisterFlag.TIME, val=row.start_time)
|
318
383
|
self.download()
|
319
384
|
|
320
|
-
def
|
385
|
+
def edit_method_timetable(self, timetable_rows: List[TimeTableEntry]):
|
321
386
|
self.get_num_rows()
|
322
387
|
self.delete_table()
|
323
388
|
res = self.get_num_rows()
|
@@ -329,7 +394,7 @@ class MethodController(TableController):
|
|
329
394
|
self.get_num_rows()
|
330
395
|
|
331
396
|
for i, row in enumerate(timetable_rows):
|
332
|
-
self.
|
397
|
+
self._edit_row(row=row, first_row=i == 0)
|
333
398
|
|
334
399
|
def stop(self):
|
335
400
|
"""
|
@@ -337,7 +402,12 @@ class MethodController(TableController):
|
|
337
402
|
"""
|
338
403
|
self.send(Command.STOP_METHOD_CMD)
|
339
404
|
|
340
|
-
def run(
|
405
|
+
def run(
|
406
|
+
self,
|
407
|
+
experiment_name: str,
|
408
|
+
add_timestamp: bool = True,
|
409
|
+
stall_while_running: bool = True,
|
410
|
+
):
|
341
411
|
"""
|
342
412
|
:param experiment_name: Name of the experiment
|
343
413
|
:param stall_while_running: whether to stall or immediately return
|
@@ -349,9 +419,19 @@ class MethodController(TableController):
|
|
349
419
|
tries = 0
|
350
420
|
while tries < 10 and not hplc_is_running:
|
351
421
|
timestamp = time.strftime(TIME_FORMAT)
|
352
|
-
self.send(
|
353
|
-
|
354
|
-
|
422
|
+
self.send(
|
423
|
+
Command.RUN_METHOD_CMD.value.format(
|
424
|
+
data_dir=self.data_dirs[0],
|
425
|
+
experiment_name=f"{experiment_name}_{timestamp}"
|
426
|
+
if add_timestamp
|
427
|
+
else experiment_name,
|
428
|
+
)
|
429
|
+
)
|
430
|
+
folder_name = (
|
431
|
+
f"{experiment_name}_{timestamp}.D"
|
432
|
+
if add_timestamp
|
433
|
+
else f"{experiment_name}.D"
|
434
|
+
)
|
355
435
|
hplc_is_running = self.check_hplc_is_running()
|
356
436
|
tries += 1
|
357
437
|
|
@@ -377,27 +457,37 @@ class MethodController(TableController):
|
|
377
457
|
warning = f"Data folder {self.data_files[-1]} may not exist, returning and will check again after run is done."
|
378
458
|
warnings.warn(warning)
|
379
459
|
|
460
|
+
def fuzzy_match_most_recent_folder(self, most_recent_folder: T) -> Result[str, str]:
|
461
|
+
if isinstance(most_recent_folder, str) or isinstance(most_recent_folder, bytes):
|
462
|
+
if os.path.exists(most_recent_folder):
|
463
|
+
return Ok(most_recent_folder)
|
464
|
+
return Err("Folder not found!")
|
465
|
+
raise ValueError("Folder is not a str or byte type.")
|
380
466
|
|
381
|
-
def
|
382
|
-
|
383
|
-
|
384
|
-
return Err("Folder not found!")
|
385
|
-
|
386
|
-
def get_data(self, custom_path: Optional[str] = None) -> AgilentChannelChromatogramData:
|
467
|
+
def get_data(
|
468
|
+
self, custom_path: Optional[str] = None
|
469
|
+
) -> AgilentChannelChromatogramData:
|
387
470
|
custom_path = custom_path if custom_path else self.data_files[-1]
|
388
471
|
self.get_spectrum_at_channels(custom_path)
|
389
|
-
return AgilentChannelChromatogramData(
|
472
|
+
return AgilentChannelChromatogramData.from_dict(self.spectra)
|
390
473
|
|
391
|
-
def get_data_uv(
|
474
|
+
def get_data_uv(
|
475
|
+
self, custom_path: Optional[str] = None
|
476
|
+
) -> dict[int, AgilentHPLCChromatogram]:
|
392
477
|
custom_path = custom_path if custom_path else self.data_files[-1]
|
393
478
|
self.get_uv_spectrum(custom_path)
|
394
479
|
return self.uv
|
395
480
|
|
396
|
-
def get_report(
|
397
|
-
|
481
|
+
def get_report(
|
482
|
+
self,
|
483
|
+
custom_path: Optional[str] = None,
|
484
|
+
report_type: ReportType = ReportType.TXT,
|
485
|
+
) -> List[AgilentReport]:
|
398
486
|
custom_path = self.data_files[-1] if not custom_path else custom_path
|
399
487
|
metd_report = self.get_report_details(custom_path, report_type)
|
400
|
-
chrom_data: List[AgilentHPLCChromatogram] = list(
|
488
|
+
chrom_data: List[AgilentHPLCChromatogram] = list(
|
489
|
+
self.get_data(custom_path).__dict__.values()
|
490
|
+
)
|
401
491
|
for i, signal in enumerate(metd_report.signals):
|
402
492
|
possible_data = chrom_data[i]
|
403
493
|
if len(possible_data.x) > 0:
|