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