pychemstation 0.5.3.dev1__py3-none-any.whl → 0.5.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.
@@ -0,0 +1,211 @@
1
+ import os
2
+ import time
3
+
4
+ from ...control.controllers.table_controller import TableController
5
+ from ...control.controllers.comm import CommunicationController
6
+ from ...utils.chromatogram import SEQUENCE_TIME_FORMAT, AgilentChannelChromatogramData
7
+ from ...utils.macro import Command
8
+ from ...utils.sequence_types import SequenceTable, SequenceEntry, SequenceDataFiles, InjectionSource, SampleType
9
+ from ...utils.table_types import TableOperation, RegisterFlag, Table
10
+
11
+
12
+ class SequenceController(TableController):
13
+ """
14
+ Class containing sequence related logic
15
+ """
16
+
17
+ def __init__(self, controller: CommunicationController, src: str, data_dir: str, table: Table, method_dir: str):
18
+ self.method_dir = method_dir
19
+ super().__init__(controller, src, data_dir, table)
20
+
21
+ def load(self) -> SequenceTable:
22
+ rows = self.get_num_rows()
23
+ self.send(Command.GET_SEQUENCE_CMD)
24
+ seq_name = self.receive()
25
+
26
+ if rows.is_ok() and seq_name.is_ok():
27
+ return SequenceTable(
28
+ name=seq_name.ok_value.string_response.partition(".S")[0],
29
+ rows=[self.get_row(r + 1) for r in range(int(rows.ok_value.num_response))])
30
+ raise RuntimeError(rows.err_value)
31
+
32
+ def get_row(self, row: int) -> SequenceEntry:
33
+ sample_name = self.get_text(row, RegisterFlag.NAME)
34
+ vial_location = int(self.get_num(row, RegisterFlag.VIAL_LOCATION))
35
+ method = self.get_text(row, RegisterFlag.METHOD)
36
+ num_inj = int(self.get_num(row, RegisterFlag.NUM_INJ))
37
+ inj_vol = int(self.get_text(row, RegisterFlag.INJ_VOL))
38
+ inj_source = InjectionSource(self.get_text(row, RegisterFlag.INJ_SOR))
39
+ sample_type = SampleType(self.get_num(row, RegisterFlag.SAMPLE_TYPE))
40
+ return SequenceEntry(sample_name=sample_name,
41
+ vial_location=vial_location,
42
+ method=None if len(method) == 0 else method,
43
+ num_inj=num_inj,
44
+ inj_vol=inj_vol,
45
+ inj_source=inj_source,
46
+ sample_type=sample_type, )
47
+
48
+ def switch(self, seq_name: str):
49
+ """
50
+ Switch to the specified sequence. The sequence name does not need the '.S' extension.
51
+
52
+ :param seq_name: The name of the sequence file
53
+ """
54
+ self.send(f'_SeqFile$ = "{seq_name}.S"')
55
+ self.send(f'_SeqPath$ = "{self.src}"')
56
+ self.send(Command.SWITCH_SEQUENCE_CMD)
57
+ time.sleep(2)
58
+ self.send(Command.GET_SEQUENCE_CMD)
59
+ time.sleep(2)
60
+ parsed_response = self.receive().value.string_response
61
+
62
+ assert parsed_response == f"{seq_name}.S", "Switching sequence failed."
63
+
64
+ def edit(self, sequence_table: SequenceTable):
65
+ """
66
+ Updates the currently loaded sequence table with the provided table. This method will delete the existing sequence table and remake it.
67
+ If you would only like to edit a single row of a sequence table, use `edit_sequence_table_row` instead.
68
+
69
+ :param sequence_table:
70
+ """
71
+
72
+ rows = self.get_num_rows()
73
+ if rows.is_ok():
74
+ existing_row_num = rows.value.num_response
75
+ wanted_row_num = len(sequence_table.rows)
76
+ while existing_row_num != wanted_row_num:
77
+ if wanted_row_num > existing_row_num:
78
+ self.add_row()
79
+ elif wanted_row_num < existing_row_num:
80
+ self.delete_row(int(existing_row_num))
81
+ self.send(Command.SAVE_SEQUENCE_CMD)
82
+ existing_row_num = self.get_num_rows().ok_value.num_response
83
+ self.send(Command.SWITCH_SEQUENCE_CMD)
84
+
85
+ for i, row in enumerate(sequence_table.rows):
86
+ self.edit_row(row=row, row_num=i + 1)
87
+ self.sleep(1)
88
+ self.send(Command.SAVE_SEQUENCE_CMD)
89
+ self.send(Command.SWITCH_SEQUENCE_CMD)
90
+
91
+ def edit_row(self, row: SequenceEntry, row_num: int):
92
+ """
93
+ Edits a row in the sequence table. If a row does NOT exist, a new one will be created.
94
+
95
+ :param row: sequence row entry with updated information
96
+ :param row_num: the row to edit, based on 1-based indexing
97
+ """
98
+ num_rows = self.get_num_rows()
99
+ if num_rows.is_ok():
100
+ while num_rows.ok_value.num_response < row_num:
101
+ self.add_row()
102
+ self.send(Command.SAVE_SEQUENCE_CMD)
103
+ num_rows = self.get_num_rows()
104
+
105
+ table_register = self.table.register
106
+ table_name = self.table.name
107
+
108
+ if row.vial_location:
109
+ loc = row.vial_location
110
+ if isinstance(row.vial_location, InjectionSource):
111
+ loc = row.vial_location.value
112
+ self.sleepy_send(TableOperation.EDIT_ROW_VAL.value.format(register=table_register,
113
+ table_name=table_name,
114
+ row=row_num,
115
+ col_name=RegisterFlag.VIAL_LOCATION,
116
+ val=loc))
117
+ if row.method:
118
+ possible_path = os.path.join(self.method_dir, row.method) + ".M\\"
119
+ method = row.method
120
+ if os.path.exists(possible_path):
121
+ method = os.path.join(self.method_dir, row.method)
122
+ self.sleepy_send(TableOperation.EDIT_ROW_TEXT.value.format(register=table_register,
123
+ table_name=table_name,
124
+ row=row_num,
125
+ col_name=RegisterFlag.METHOD,
126
+ val=method))
127
+
128
+ if row.num_inj:
129
+ self.sleepy_send(TableOperation.EDIT_ROW_VAL.value.format(register=table_register,
130
+ table_name=table_name,
131
+ row=row_num,
132
+ col_name=RegisterFlag.NUM_INJ,
133
+ val=row.num_inj))
134
+
135
+ if row.inj_vol:
136
+ self.sleepy_send(TableOperation.EDIT_ROW_TEXT.value.format(register=table_register,
137
+ table_name=table_name,
138
+ row=row_num,
139
+ col_name=RegisterFlag.INJ_VOL,
140
+ val=row.inj_vol))
141
+
142
+ if row.inj_source:
143
+ self.sleepy_send(TableOperation.EDIT_ROW_TEXT.value.format(register=table_register,
144
+ table_name=table_name,
145
+ row=row_num,
146
+ col_name=RegisterFlag.INJ_SOR,
147
+ val=row.inj_source.value))
148
+
149
+ if row.sample_name:
150
+ self.sleepy_send(TableOperation.EDIT_ROW_TEXT.value.format(register=table_register,
151
+ table_name=table_name,
152
+ row=row_num,
153
+ col_name=RegisterFlag.NAME,
154
+ val=row.sample_name))
155
+ self.sleepy_send(TableOperation.EDIT_ROW_TEXT.value.format(register=table_register,
156
+ table_name=table_name,
157
+ row=row_num,
158
+ col_name=RegisterFlag.DATA_FILE,
159
+ val=row.sample_name))
160
+ if row.sample_type:
161
+ self.sleepy_send(TableOperation.EDIT_ROW_VAL.value.format(register=table_register,
162
+ table_name=table_name,
163
+ row=row_num,
164
+ col_name=RegisterFlag.SAMPLE_TYPE,
165
+ val=row.sample_type.value))
166
+
167
+ self.send(Command.SAVE_SEQUENCE_CMD)
168
+
169
+ def run(self):
170
+ """
171
+ Starts the currently loaded sequence, storing data
172
+ under the <data_dir>/<sequence table name> folder.
173
+ Device must be ready.
174
+ """
175
+ timestamp = time.strftime(SEQUENCE_TIME_FORMAT)
176
+ seq_table = self.load()
177
+ self.send(Command.RUN_SEQUENCE_CMD.value)
178
+
179
+ if self.check_hplc_is_running():
180
+ folder_name = f"{seq_table.name} {timestamp}"
181
+ self.data_files.append(SequenceDataFiles(dir=folder_name,
182
+ sequence_name=seq_table.name))
183
+
184
+ run_completed = self.check_hplc_done_running(sequence=seq_table)
185
+
186
+ if run_completed.is_ok():
187
+ self.data_files[-1].dir = run_completed.value
188
+ else:
189
+ raise RuntimeError("Run error has occured.")
190
+
191
+ def retrieve_recent_data_files(self):
192
+ sequence_data_files: SequenceDataFiles = self.data_files[-1]
193
+ return sequence_data_files.dir
194
+
195
+ def get_data(self) -> list[AgilentChannelChromatogramData]:
196
+ parent_dir = self.data_files[-1].dir
197
+ subdirs = [x[0] for x in os.walk(self.data_dir)]
198
+ potential_folders = sorted(list(filter(lambda d: parent_dir in d, subdirs)))
199
+ self.data_files[-1].child_dirs = [f for f in potential_folders if
200
+ parent_dir in f and ".M" not in f and ".D" in f]
201
+
202
+ spectra: list[AgilentChannelChromatogramData] = []
203
+ for row in self.data_files[-1].child_dirs:
204
+ self.get_spectrum(row)
205
+ spectra.append(
206
+ AgilentChannelChromatogramData(
207
+ A=self.spectra["A"],
208
+ B=self.spectra["B"],
209
+ C=self.spectra["C"],
210
+ D=self.spectra["D"]))
211
+ return spectra
@@ -0,0 +1,198 @@
1
+ """
2
+ Abstract module containing shared logic for Method and Sequence tables.
3
+
4
+ Authors: Lucy Hao
5
+ """
6
+
7
+ import abc
8
+ import os
9
+ import time
10
+ from typing import Union, Optional
11
+
12
+ import polling
13
+ from result import Result, Ok, Err
14
+
15
+ from ...control.controllers.comm import CommunicationController
16
+ from ...utils.chromatogram import AgilentHPLCChromatogram, AgilentChannelChromatogramData
17
+ from ...utils.macro import Command, HPLCRunningStatus, Response
18
+ from ...utils.method_types import MethodTimetable
19
+ from ...utils.sequence_types import SequenceDataFiles, SequenceTable
20
+ from ...utils.table_types import Table, TableOperation, RegisterFlag
21
+
22
+
23
+ class TableController(abc.ABC):
24
+
25
+ def __init__(self, controller: CommunicationController, src: str, data_dir: str, table: Table):
26
+ self.controller = controller
27
+ self.table = table
28
+
29
+ if os.path.isdir(src):
30
+ self.src: str = src
31
+ else:
32
+ raise FileNotFoundError(f"dir: {src} not found.")
33
+
34
+ if os.path.isdir(data_dir):
35
+ self.data_dir: str = data_dir
36
+ else:
37
+ raise FileNotFoundError(f"dir: {data_dir} not found.")
38
+
39
+ self.spectra: dict[str, AgilentHPLCChromatogram] = {
40
+ "A": AgilentHPLCChromatogram(self.data_dir),
41
+ "B": AgilentHPLCChromatogram(self.data_dir),
42
+ "C": AgilentHPLCChromatogram(self.data_dir),
43
+ "D": AgilentHPLCChromatogram(self.data_dir),
44
+ }
45
+
46
+ self.data_files: Union[list[SequenceDataFiles], list[str]] = []
47
+
48
+ def receive(self) -> Result[Response, str]:
49
+ for _ in range(10):
50
+ try:
51
+ return self.controller.receive()
52
+ except IndexError:
53
+ continue
54
+ return Err("Could not parse response")
55
+
56
+ def send(self, cmd: Union[Command, str]):
57
+ self.controller.send(cmd)
58
+
59
+ def sleepy_send(self, cmd: Union[Command, str]):
60
+ self.controller.sleepy_send(cmd)
61
+
62
+ def sleep(self, seconds: int):
63
+ """
64
+ Tells the HPLC to wait for a specified number of seconds.
65
+
66
+ :param seconds: number of seconds to wait
67
+ """
68
+ self.send(Command.SLEEP_CMD.value.format(seconds=seconds))
69
+
70
+ def get_num(self, row: int, col_name: RegisterFlag) -> float:
71
+ return self.controller.get_num_val(TableOperation.GET_ROW_VAL.value.format(register=self.table.register,
72
+ table_name=self.table.name,
73
+ row=row,
74
+ col_name=col_name.value))
75
+
76
+ def get_text(self, row: int, col_name: RegisterFlag) -> str:
77
+ return self.controller.get_text_val(TableOperation.GET_ROW_TEXT.value.format(register=self.table.register,
78
+ table_name=self.table.name,
79
+ row=row,
80
+ col_name=col_name.value))
81
+
82
+ @abc.abstractmethod
83
+ def get_row(self, row: int):
84
+ pass
85
+
86
+ def delete_row(self, row: int):
87
+ self.sleepy_send(TableOperation.DELETE_ROW.value.format(register=self.table.register,
88
+ table_name=self.table.name,
89
+ row=row))
90
+
91
+ def add_row(self):
92
+ """
93
+ Adds a row to the provided table for currently loaded method or sequence.
94
+ Import either the SEQUENCE_TABLE or METHOD_TIMETABLE from hein_analytical_control.constants.
95
+ You can also provide your own table.
96
+
97
+ :param table: the table to add a new row to
98
+ """
99
+ self.sleepy_send(TableOperation.NEW_ROW.value.format(register=self.table.register,
100
+ table_name=self.table.name))
101
+
102
+ def delete_table(self):
103
+ """
104
+ Deletes the table for the current loaded method or sequence.
105
+ Import either the SEQUENCE_TABLE or METHOD_TIMETABLE from hein_analytical_control.constants.
106
+ You can also provide your own table.
107
+
108
+ :param table: the table to delete
109
+ """
110
+ self.sleepy_send(TableOperation.DELETE_TABLE.value.format(register=self.table.register,
111
+ table_name=self.table.name))
112
+
113
+ def new_table(self):
114
+ """
115
+ Creates the table for the currently loaded method or sequence. Import either the SEQUENCE_TABLE or
116
+ METHOD_TIMETABLE from hein_analytical_control.constants. You can also provide your own table.
117
+
118
+ :param table: the table to create
119
+ """
120
+ self.send(TableOperation.CREATE_TABLE.value.format(register=self.table.register,
121
+ table_name=self.table.name))
122
+
123
+ def get_num_rows(self) -> Result[int, str]:
124
+ self.send(TableOperation.GET_NUM_ROWS.value.format(register=self.table.register,
125
+ table_name=self.table.name,
126
+ col_name=RegisterFlag.NUM_ROWS))
127
+ self.send(Command.GET_ROWS_CMD.value.format(register=self.table.register,
128
+ table_name=self.table.name,
129
+ col_name=RegisterFlag.NUM_ROWS))
130
+ res = self.controller.receive()
131
+
132
+ if res.is_ok():
133
+ self.send("Sleep 0.1")
134
+ self.send('Print Rows')
135
+ return res
136
+ else:
137
+ return Err("No rows could be read.")
138
+
139
+ def check_hplc_is_running(self) -> bool:
140
+ started_running = polling.poll(
141
+ lambda: isinstance(self.controller.get_status(), HPLCRunningStatus),
142
+ step=30,
143
+ max_tries=10)
144
+ return started_running
145
+
146
+ def check_hplc_done_running(self,
147
+ method: Optional[MethodTimetable] = None,
148
+ sequence: Optional[SequenceTable] = None) -> Result[str, str]:
149
+ """
150
+ Checks if ChemStation has finished running and can read data back
151
+
152
+ :param method: if you are running a method and want to read back data, the timeout period will be adjusted to be longer than the method's runtime
153
+ :return: Return True if data can be read back, else False.
154
+ """
155
+ timeout = 10 * 60
156
+ if method:
157
+ timeout = ((method.first_row.maximum_run_time + 2) * 60)
158
+ if sequence:
159
+ timeout *= len(sequence.rows)
160
+
161
+ most_recent_folder = self.retrieve_recent_data_files()
162
+ finished_run = polling.poll(
163
+ lambda: self.controller.check_if_running(),
164
+ timeout=timeout,
165
+ step=60
166
+ )
167
+
168
+ if finished_run:
169
+ if os.path.exists(most_recent_folder):
170
+ return Ok(most_recent_folder)
171
+ else:
172
+ subdirs = [x[0] for x in os.walk(self.data_dir)]
173
+ potential_folders = sorted(list(filter(lambda d: most_recent_folder in d, subdirs)))
174
+ parent_dirs = []
175
+ for folder in potential_folders:
176
+ path = os.path.normpath(folder)
177
+ split_folder = path.split(os.sep)
178
+ if most_recent_folder in split_folder[-1]:
179
+ parent_dirs.append(folder)
180
+ parent_dir = sorted(parent_dirs, reverse=True)[0]
181
+ return Ok(parent_dir)
182
+ else:
183
+ return Err("Run did not complete as expected")
184
+
185
+ @abc.abstractmethod
186
+ def retrieve_recent_data_files(self):
187
+ pass
188
+
189
+ @abc.abstractmethod
190
+ def get_data(self) -> Union[list[AgilentChannelChromatogramData], AgilentChannelChromatogramData]:
191
+ pass
192
+
193
+ def get_spectrum(self, data_file: str):
194
+ """
195
+ Load chromatogram for any channel in spectra dictionary.
196
+ """
197
+ for channel, spec in self.spectra.items():
198
+ spec.load_spectrum(data_path=data_file, channel=channel)
@@ -6,9 +6,8 @@ Authors: Lucy Hao
6
6
 
7
7
  from typing import Union, Optional
8
8
 
9
- from ..control import CommunicationController
10
- from ..control.table import MethodController, SequenceController
11
- from ..utils.chromatogram import AgilentHPLCChromatogram
9
+ from ..control.controllers import MethodController, SequenceController, CommunicationController
10
+ from ..utils.chromatogram import AgilentHPLCChromatogram, AgilentChannelChromatogramData
12
11
  from ..utils.macro import Command, HPLCRunningStatus, HPLCAvailStatus, HPLCErrorStatus, Response
13
12
  from ..utils.method_types import MethodTimetable
14
13
  from ..utils.sequence_types import SequenceTable, SequenceEntry
@@ -65,8 +64,8 @@ class HPLCController:
65
64
  only 'General-Poroshell' is needed.
66
65
 
67
66
  :param method_name: any available method in Chemstation method directory
68
- :raise IndexError: Response did not have expected format. Try again.
69
- :raise AssertionError: The desired method is not selected. Try again.
67
+ :raises IndexError: Response did not have expected format. Try again.
68
+ :raises AssertionError: The desired method is not selected. Try again.
70
69
  """
71
70
  self.method_controller.switch(method_name)
72
71
 
@@ -91,15 +90,15 @@ class HPLCController:
91
90
  """
92
91
  self.method_controller.run(experiment_name)
93
92
 
94
- def run_sequence(self, sequence_table: SequenceTable):
93
+ def run_sequence(self):
95
94
  """
96
95
  Starts the currently loaded sequence, storing data
97
96
  under the <data_dir>/<sequence table name> folder.
98
97
  Device must be ready.
99
98
 
100
- :param sequence_table:
99
+ :param sequence_name:
101
100
  """
102
- self.sequence_controller.run(sequence_table)
101
+ self.sequence_controller.run()
103
102
 
104
103
  def edit_method(self, updated_method: MethodTimetable, save: bool = False):
105
104
  """Updated the currently loaded method in ChemStation with provided values.
@@ -114,7 +113,7 @@ class HPLCController:
114
113
  Updates the currently loaded sequence table with the provided table. This method will delete the existing sequence table and remake it.
115
114
  If you would only like to edit a single row of a sequence table, use `edit_sequence_row` instead.
116
115
 
117
- :param sequence_table:
116
+ :param updated_sequence:
118
117
  """
119
118
  self.sequence_controller.edit(updated_sequence)
120
119
 
@@ -127,13 +126,13 @@ class HPLCController:
127
126
  """
128
127
  self.sequence_controller.edit_row(row, num)
129
128
 
130
- def get_last_run_method_data(self) -> dict[str, AgilentHPLCChromatogram]:
129
+ def get_last_run_method_data(self) -> AgilentChannelChromatogramData:
131
130
  """
132
131
  Returns the last run method data.
133
132
  """
134
133
  return self.method_controller.get_data()
135
134
 
136
- def get_last_run_sequence_data(self) -> list[dict[str, AgilentHPLCChromatogram]]:
135
+ def get_last_run_sequence_data(self) -> list[AgilentChannelChromatogramData]:
137
136
  """
138
137
  Returns data for all rows in the last run sequence data.
139
138
  """
@@ -30,7 +30,7 @@ class SequenceController(TableController):
30
30
 
31
31
  if rows.is_ok() and seq_name.is_ok():
32
32
  return SequenceTable(
33
- name=seq_name.ok_value.num_response,
33
+ name=seq_name.ok_value.string_response.partition(".S")[0],
34
34
  rows=[self.get_row(r + 1) for r in range(int(rows.ok_value.num_response))])
35
35
  raise RuntimeError(rows.err_value)
36
36
 
@@ -73,34 +73,25 @@ class SequenceController(TableController):
73
73
 
74
74
  :param sequence_table:
75
75
  """
76
- self.send("Local Rows")
77
- self.sleep(1)
78
- self.delete_table()
79
- self.sleep(1)
80
- self.new_table()
81
- self.sleep(1)
82
- self.get_num_rows()
83
-
84
- if True:
85
- for _ in sequence_table.rows:
86
- self.add_row()
87
- self.sleep(1)
76
+
77
+ rows = self.get_num_rows()
78
+ if rows.is_ok():
79
+ existing_row_num = rows.value.num_response
80
+ wanted_row_num = len(sequence_table.rows)
81
+ while existing_row_num != wanted_row_num:
82
+ if wanted_row_num > existing_row_num:
83
+ self.add_row()
84
+ elif wanted_row_num < existing_row_num:
85
+ self.delete_row(int(existing_row_num))
88
86
  self.send(Command.SAVE_SEQUENCE_CMD)
89
- self.get_num_rows()
90
- self.send(Command.SAVE_SEQUENCE_CMD)
87
+ existing_row_num = self.get_num_rows().ok_value.num_response
88
+ self.send(Command.SWITCH_SEQUENCE_CMD)
89
+
91
90
  for i, row in enumerate(sequence_table.rows):
92
91
  self.edit_row(row=row, row_num=i + 1)
93
92
  self.sleep(1)
94
93
  self.send(Command.SAVE_SEQUENCE_CMD)
95
- else:
96
- for i, row in enumerate(sequence_table.rows):
97
- self.add_row()
98
- self.sleep(0.1)
99
- self.edit_row(row=row, row_num=i + 1)
100
- self.sleep(0.1)
101
- rows = self.get_num_rows()
102
- self.send(Command.SAVE_SEQUENCE_CMD)
103
- self.send(Command.SWITCH_SEQUENCE_CMD)
94
+ self.send(Command.SWITCH_SEQUENCE_CMD)
104
95
 
105
96
  def edit_row(self, row: SequenceEntry, row_num: int):
106
97
  """
@@ -120,13 +111,16 @@ class SequenceController(TableController):
120
111
  table_name = self.table.name
121
112
 
122
113
  if row.vial_location:
114
+ loc = row.vial_location
115
+ if isinstance(row.vial_location, InjectionSource):
116
+ loc = row.vial_location.value
123
117
  self.sleepy_send(TableOperation.EDIT_ROW_VAL.value.format(register=table_register,
124
118
  table_name=table_name,
125
119
  row=row_num,
126
120
  col_name=RegisterFlag.VIAL_LOCATION,
127
- val=row.vial_location.value))
121
+ val=loc))
128
122
  if row.method:
129
- possible_path = os.path.join(self.method_dir, row.method)
123
+ possible_path = os.path.join(self.method_dir, row.method) + ".M\\"
130
124
  method = row.method
131
125
  if os.path.exists(possible_path):
132
126
  method = os.path.join(self.method_dir, row.method)
@@ -177,23 +171,22 @@ class SequenceController(TableController):
177
171
 
178
172
  self.send(Command.SAVE_SEQUENCE_CMD)
179
173
 
180
- def run(self, sequence_table: SequenceTable):
174
+ def run(self):
181
175
  """
182
176
  Starts the currently loaded sequence, storing data
183
177
  under the <data_dir>/<sequence table name> folder.
184
178
  Device must be ready.
185
-
186
- :param sequence_table:
187
179
  """
188
180
  timestamp = time.strftime(SEQUENCE_TIME_FORMAT)
181
+ seq_table = self.load()
189
182
  self.send(Command.RUN_SEQUENCE_CMD.value)
190
183
 
191
184
  if self.check_hplc_is_running():
192
- folder_name = f"{sequence_table.name} {timestamp}"
185
+ folder_name = f"{seq_table.name} {timestamp}"
193
186
  self.data_files.append(SequenceDataFiles(dir=folder_name,
194
- sequence_name=sequence_table.name, ))
187
+ sequence_name=seq_table.name))
195
188
 
196
- run_completed = self.check_hplc_done_running()
189
+ run_completed = self.check_hplc_done_running(sequence=seq_table)
197
190
 
198
191
  if run_completed.is_ok():
199
192
  self.data_files[-1].dir = run_completed.value
@@ -202,16 +195,16 @@ class SequenceController(TableController):
202
195
 
203
196
  def retrieve_recent_data_files(self):
204
197
  sequence_data_files: SequenceDataFiles = self.data_files[-1]
205
- return os.path.join(sequence_data_files.dir, sequence_data_files.child_dirs[-1])
198
+ return sequence_data_files.dir
206
199
 
207
200
  def get_data(self) -> list[dict[str, AgilentHPLCChromatogram]]:
208
- sequence_data_files: SequenceDataFiles = self.data_files[-1]
201
+ parent_dir = self.data_files[-1].dir
209
202
  subdirs = [x[0] for x in os.walk(self.data_dir)]
210
- potential_folders = sorted(list(filter(lambda d: sequence_data_files.dir in d, subdirs)))
211
- self.data_files[-1].child_dirs = potential_folders
203
+ potential_folders = sorted(list(filter(lambda d: parent_dir in d, subdirs)))
204
+ self.data_files[-1].child_dirs = [f for f in potential_folders if parent_dir in f and ".M" not in f and ".D" in f]
205
+
212
206
  spectra: list[dict[str, AgilentHPLCChromatogram]] = []
213
- for row in sequence_data_files.child_dirs:
214
- data_path = os.path.join(sequence_data_files.dir, row)
215
- self.get_spectrum(data_path)
207
+ for row in self.data_files[-1].child_dirs:
208
+ self.get_spectrum(row)
216
209
  spectra.append(deepcopy(self.spectra))
217
210
  return spectra