pychemstation 0.5.5__py3-none-any.whl → 0.5.6.dev1__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 +19 -9
- pychemstation/control/controllers/sequence.py +18 -16
- pychemstation/control/controllers/table_controller.py +32 -22
- pychemstation/control/table/table_controller.py +19 -16
- pychemstation/utils/chromatogram.py +1 -1
- {pychemstation-0.5.5.dist-info → pychemstation-0.5.6.dev1.dist-info}/METADATA +1 -1
- {pychemstation-0.5.5.dist-info → pychemstation-0.5.6.dev1.dist-info}/RECORD +11 -11
- tests/test_comb.py +2 -2
- {pychemstation-0.5.5.dist-info → pychemstation-0.5.6.dev1.dist-info}/LICENSE +0 -0
- {pychemstation-0.5.5.dist-info → pychemstation-0.5.6.dev1.dist-info}/WHEEL +0 -0
- {pychemstation-0.5.5.dist-info → pychemstation-0.5.6.dev1.dist-info}/top_level.txt +0 -0
@@ -51,9 +51,10 @@ class MethodController(TableController):
|
|
51
51
|
rows = self.get_num_rows()
|
52
52
|
if rows.is_ok():
|
53
53
|
timetable_rows = [self.get_row(r + 1) for r in range(int(rows.ok_value.num_response))]
|
54
|
-
|
54
|
+
self.table_state = MethodTimetable(
|
55
55
|
first_row=self.get_method_params(),
|
56
56
|
subsequent_rows=timetable_rows)
|
57
|
+
return self.table_state
|
57
58
|
else:
|
58
59
|
raise RuntimeError(rows.err_value)
|
59
60
|
|
@@ -88,6 +89,7 @@ class MethodController(TableController):
|
|
88
89
|
if res.is_ok():
|
89
90
|
parsed_response = res.ok_value.string_response
|
90
91
|
assert parsed_response == f"{method_name}.M", "Switching Methods failed."
|
92
|
+
self.table_state = None
|
91
93
|
|
92
94
|
def load_from_disk(self, method_name: str) -> MethodTimetable:
|
93
95
|
"""
|
@@ -118,7 +120,7 @@ class MethodController(TableController):
|
|
118
120
|
elif solvent.channel == "Channel_B":
|
119
121
|
organic_modifier = solvent
|
120
122
|
|
121
|
-
|
123
|
+
self.table_state = MethodTimetable(
|
122
124
|
first_row=HPLCMethodParams(
|
123
125
|
organic_modifier=organic_modifier.percentage,
|
124
126
|
flow=method.flow,
|
@@ -135,6 +137,7 @@ class MethodController(TableController):
|
|
135
137
|
organic_modifier=organic_modifier,
|
136
138
|
modifier_a=aq_modifier
|
137
139
|
)
|
140
|
+
return self.table_state
|
138
141
|
else:
|
139
142
|
raise FileNotFoundError
|
140
143
|
|
@@ -242,7 +245,7 @@ class MethodController(TableController):
|
|
242
245
|
"""
|
243
246
|
self.send(Command.STOP_METHOD_CMD)
|
244
247
|
|
245
|
-
def run(self, experiment_name: str):
|
248
|
+
def run(self, experiment_name: str, stall_while_running: bool = True):
|
246
249
|
"""
|
247
250
|
This is the preferred method to trigger a run.
|
248
251
|
Starts the currently selected method, storing data
|
@@ -261,14 +264,21 @@ class MethodController(TableController):
|
|
261
264
|
folder_name = f"{experiment_name}_{timestamp}.D"
|
262
265
|
self.data_files.append(os.path.join(self.data_dir, folder_name))
|
263
266
|
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
267
|
+
if stall_while_running:
|
268
|
+
run_completed = self.check_hplc_done_running(method=self.table_state)
|
269
|
+
if run_completed.is_ok():
|
270
|
+
self.data_files[-1] = run_completed.value
|
271
|
+
else:
|
272
|
+
raise RuntimeError("Run error has occurred.")
|
273
|
+
else:
|
274
|
+
self.data_files[-1].dir = self.fuzzy_match_most_recent_folder(folder_name).ok_value
|
268
275
|
|
269
276
|
def retrieve_recent_data_files(self) -> str:
|
270
277
|
return self.data_files[-1]
|
271
278
|
|
272
|
-
def get_data(self) -> AgilentChannelChromatogramData:
|
273
|
-
|
279
|
+
def get_data(self, custom_path: Optional[str] = None) -> AgilentChannelChromatogramData:
|
280
|
+
if not custom_path:
|
281
|
+
self.get_spectrum(self.data_files[-1])
|
282
|
+
else:
|
283
|
+
self.get_spectrum(custom_path)
|
274
284
|
return AgilentChannelChromatogramData(**self.spectra)
|
@@ -1,3 +1,6 @@
|
|
1
|
+
from typing import Optional
|
2
|
+
|
3
|
+
|
1
4
|
import os
|
2
5
|
import time
|
3
6
|
|
@@ -24,9 +27,10 @@ class SequenceController(TableController):
|
|
24
27
|
seq_name = self.receive()
|
25
28
|
|
26
29
|
if rows.is_ok() and seq_name.is_ok():
|
27
|
-
|
30
|
+
self.table_state = SequenceTable(
|
28
31
|
name=seq_name.ok_value.string_response.partition(".S")[0],
|
29
32
|
rows=[self.get_row(r + 1) for r in range(int(rows.ok_value.num_response))])
|
33
|
+
return self.table_state
|
30
34
|
raise RuntimeError(rows.err_value)
|
31
35
|
|
32
36
|
def get_row(self, row: int) -> SequenceEntry:
|
@@ -60,6 +64,7 @@ class SequenceController(TableController):
|
|
60
64
|
parsed_response = self.receive().value.string_response
|
61
65
|
|
62
66
|
assert parsed_response == f"{seq_name}.S", "Switching sequence failed."
|
67
|
+
self.table_state = None
|
63
68
|
|
64
69
|
def edit(self, sequence_table: SequenceTable):
|
65
70
|
"""
|
@@ -166,7 +171,7 @@ class SequenceController(TableController):
|
|
166
171
|
|
167
172
|
self.send(Command.SAVE_SEQUENCE_CMD)
|
168
173
|
|
169
|
-
def run(self):
|
174
|
+
def run(self, stall_while_running: bool = True):
|
170
175
|
"""
|
171
176
|
Starts the currently loaded sequence, storing data
|
172
177
|
under the <data_dir>/<sequence table name> folder.
|
@@ -181,19 +186,21 @@ class SequenceController(TableController):
|
|
181
186
|
self.data_files.append(SequenceDataFiles(dir=folder_name,
|
182
187
|
sequence_name=seq_table.name))
|
183
188
|
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
189
|
+
if stall_while_running:
|
190
|
+
run_completed = self.check_hplc_done_running(sequence=seq_table)
|
191
|
+
if run_completed.is_ok():
|
192
|
+
self.data_files[-1].dir = run_completed.value
|
193
|
+
else:
|
194
|
+
raise RuntimeError("Run error has occurred.")
|
195
|
+
else:
|
196
|
+
self.data_files[-1].dir = self.fuzzy_match_most_recent_folder(folder_name).ok_value
|
190
197
|
|
191
198
|
def retrieve_recent_data_files(self):
|
192
199
|
sequence_data_files: SequenceDataFiles = self.data_files[-1]
|
193
200
|
return sequence_data_files.dir
|
194
201
|
|
195
|
-
def get_data(self) -> list[AgilentChannelChromatogramData]:
|
196
|
-
parent_dir = self.data_files[-1].dir
|
202
|
+
def get_data(self, custom_path:Optional[str] = None ) -> list[AgilentChannelChromatogramData]:
|
203
|
+
parent_dir = self.data_files[-1].dir if not custom_path else custom_path
|
197
204
|
subdirs = [x[0] for x in os.walk(self.data_dir)]
|
198
205
|
potential_folders = sorted(list(filter(lambda d: parent_dir in d, subdirs)))
|
199
206
|
self.data_files[-1].child_dirs = [f for f in potential_folders if
|
@@ -202,10 +209,5 @@ class SequenceController(TableController):
|
|
202
209
|
spectra: list[AgilentChannelChromatogramData] = []
|
203
210
|
for row in self.data_files[-1].child_dirs:
|
204
211
|
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"]))
|
212
|
+
spectra.append(AgilentChannelChromatogramData(**self.spectra))
|
211
213
|
return spectra
|
@@ -6,7 +6,6 @@ Authors: Lucy Hao
|
|
6
6
|
|
7
7
|
import abc
|
8
8
|
import os
|
9
|
-
import time
|
10
9
|
from typing import Union, Optional
|
11
10
|
|
12
11
|
import polling
|
@@ -25,6 +24,7 @@ class TableController(abc.ABC):
|
|
25
24
|
def __init__(self, controller: CommunicationController, src: str, data_dir: str, table: Table):
|
26
25
|
self.controller = controller
|
27
26
|
self.table = table
|
27
|
+
self.table_state : Optional[TableController] = None
|
28
28
|
|
29
29
|
if os.path.isdir(src):
|
30
30
|
self.src: str = src
|
@@ -120,7 +120,7 @@ class TableController(abc.ABC):
|
|
120
120
|
self.send(TableOperation.CREATE_TABLE.value.format(register=self.table.register,
|
121
121
|
table_name=self.table.name))
|
122
122
|
|
123
|
-
def get_num_rows(self) -> Result[
|
123
|
+
def get_num_rows(self) -> Result[Response, str]:
|
124
124
|
self.send(TableOperation.GET_NUM_ROWS.value.format(register=self.table.register,
|
125
125
|
table_name=self.table.name,
|
126
126
|
col_name=RegisterFlag.NUM_ROWS))
|
@@ -139,8 +139,8 @@ class TableController(abc.ABC):
|
|
139
139
|
def check_hplc_is_running(self) -> bool:
|
140
140
|
started_running = polling.poll(
|
141
141
|
lambda: isinstance(self.controller.get_status(), HPLCRunningStatus),
|
142
|
-
step=
|
143
|
-
max_tries=
|
142
|
+
step=5,
|
143
|
+
max_tries=100)
|
144
144
|
return started_running
|
145
145
|
|
146
146
|
def check_hplc_done_running(self,
|
@@ -154,7 +154,7 @@ class TableController(abc.ABC):
|
|
154
154
|
"""
|
155
155
|
timeout = 10 * 60
|
156
156
|
if method:
|
157
|
-
timeout = ((method.first_row.maximum_run_time +
|
157
|
+
timeout = ((method.first_row.maximum_run_time + 5) * 60)
|
158
158
|
if sequence:
|
159
159
|
timeout *= len(sequence.rows)
|
160
160
|
|
@@ -162,26 +162,36 @@ class TableController(abc.ABC):
|
|
162
162
|
finished_run = polling.poll(
|
163
163
|
lambda: self.controller.check_if_running(),
|
164
164
|
timeout=timeout,
|
165
|
-
step=
|
166
|
-
|
167
|
-
|
168
|
-
if finished_run:
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
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)
|
165
|
+
step=18)
|
166
|
+
|
167
|
+
check_folder = self.fuzzy_match_most_recent_folder(most_recent_folder)
|
168
|
+
if check_folder.is_ok() and finished_run:
|
169
|
+
return check_folder
|
170
|
+
elif check_folder.is_ok():
|
171
|
+
finished_run = polling.poll(
|
172
|
+
lambda: self.controller.check_if_running(),
|
173
|
+
timeout=timeout,
|
174
|
+
step=12)
|
175
|
+
if finished_run:
|
176
|
+
return check_folder
|
182
177
|
else:
|
183
178
|
return Err("Run did not complete as expected")
|
184
179
|
|
180
|
+
def fuzzy_match_most_recent_folder(self, most_recent_folder) -> Result[str, str]:
|
181
|
+
if os.path.exists(most_recent_folder):
|
182
|
+
return Ok(most_recent_folder)
|
183
|
+
|
184
|
+
subdirs = [x[0] for x in os.walk(self.data_dir)]
|
185
|
+
potential_folders = sorted(list(filter(lambda d: most_recent_folder in d, subdirs)))
|
186
|
+
parent_dirs = []
|
187
|
+
for folder in potential_folders:
|
188
|
+
path = os.path.normpath(folder)
|
189
|
+
split_folder = path.split(os.sep)
|
190
|
+
if most_recent_folder in split_folder[-1]:
|
191
|
+
parent_dirs.append(folder)
|
192
|
+
parent_dir = sorted(parent_dirs, reverse=True)[0]
|
193
|
+
return Ok(parent_dir)
|
194
|
+
|
185
195
|
@abc.abstractmethod
|
186
196
|
def retrieve_recent_data_files(self):
|
187
197
|
pass
|
@@ -12,8 +12,8 @@ from typing import Union, Optional
|
|
12
12
|
import polling
|
13
13
|
from result import Result, Ok, Err
|
14
14
|
|
15
|
-
from ...control import CommunicationController
|
16
|
-
from ...utils.chromatogram import AgilentHPLCChromatogram
|
15
|
+
from ...control.controllers.comm import CommunicationController
|
16
|
+
from ...utils.chromatogram import AgilentHPLCChromatogram, AgilentChannelChromatogramData
|
17
17
|
from ...utils.macro import Command, HPLCRunningStatus, Response
|
18
18
|
from ...utils.method_types import MethodTimetable
|
19
19
|
from ...utils.sequence_types import SequenceDataFiles, SequenceTable
|
@@ -139,8 +139,8 @@ class TableController(abc.ABC):
|
|
139
139
|
def check_hplc_is_running(self) -> bool:
|
140
140
|
started_running = polling.poll(
|
141
141
|
lambda: isinstance(self.controller.get_status(), HPLCRunningStatus),
|
142
|
-
step=
|
143
|
-
max_tries=
|
142
|
+
step=5,
|
143
|
+
max_tries=100)
|
144
144
|
return started_running
|
145
145
|
|
146
146
|
def check_hplc_done_running(self,
|
@@ -162,32 +162,35 @@ class TableController(abc.ABC):
|
|
162
162
|
finished_run = polling.poll(
|
163
163
|
lambda: self.controller.check_if_running(),
|
164
164
|
timeout=timeout,
|
165
|
-
step=
|
165
|
+
step=12
|
166
166
|
)
|
167
167
|
|
168
168
|
if finished_run:
|
169
169
|
if os.path.exists(most_recent_folder):
|
170
170
|
return Ok(most_recent_folder)
|
171
171
|
else:
|
172
|
-
|
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)
|
172
|
+
return self.fuzzy_match_most_recent_folder(most_recent_folder)
|
182
173
|
else:
|
183
174
|
return Err("Run did not complete as expected")
|
184
175
|
|
176
|
+
def fuzzy_match_most_recent_folder(self, most_recent_folder) -> Result[str, str]:
|
177
|
+
subdirs = [x[0] for x in os.walk(self.data_dir)]
|
178
|
+
potential_folders = sorted(list(filter(lambda d: most_recent_folder in d, subdirs)))
|
179
|
+
parent_dirs = []
|
180
|
+
for folder in potential_folders:
|
181
|
+
path = os.path.normpath(folder)
|
182
|
+
split_folder = path.split(os.sep)
|
183
|
+
if most_recent_folder in split_folder[-1]:
|
184
|
+
parent_dirs.append(folder)
|
185
|
+
parent_dir = sorted(parent_dirs, reverse=True)[0]
|
186
|
+
return Ok(parent_dir)
|
187
|
+
|
185
188
|
@abc.abstractmethod
|
186
189
|
def retrieve_recent_data_files(self):
|
187
190
|
pass
|
188
191
|
|
189
192
|
@abc.abstractmethod
|
190
|
-
def get_data(self) ->
|
193
|
+
def get_data(self) -> Union[list[AgilentChannelChromatogramData], AgilentChannelChromatogramData]:
|
191
194
|
pass
|
192
195
|
|
193
196
|
def get_spectrum(self, data_file: str):
|
@@ -8,18 +8,18 @@ pychemstation/control/comm.py,sha256=u44g1hTluQ0yUG93Un-QAshScoDpgYRrZfFTgweP5tY
|
|
8
8
|
pychemstation/control/hplc.py,sha256=L1-cBQ7-thuITx1Mqq3lYXo832nEQtRJEX7nlLvRYrg,6732
|
9
9
|
pychemstation/control/controllers/__init__.py,sha256=di3ytLIK-35XC_THw4IjNaOtCUTe7GuEOFb-obmREw4,166
|
10
10
|
pychemstation/control/controllers/comm.py,sha256=iltKMNfdp_8INA5Vss9asI2LxJam_Ro3YWBHBQFr4t0,7353
|
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=GNGvGUF9LUCcHAe37SIdnQQ_RzwgnU2ba1oWLXnOp8w,12816
|
12
|
+
pychemstation/control/controllers/sequence.py,sha256=f4ZhzkM2hY8xk8dUyiCpmZ5fwU4ev2-CNSbyFeFVe_w,10963
|
13
|
+
pychemstation/control/controllers/table_controller.py,sha256=DnusCG5ySR8gA-oe3K_EJfAPlYhmW33epiCi4YVUKJg,8648
|
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
|
17
|
-
pychemstation/control/table/table_controller.py,sha256=
|
17
|
+
pychemstation/control/table/table_controller.py,sha256=HVNYUXqtyFTAvb67fa3RO5RHgmBTFMsYRHKpiXdYcfs,8313
|
18
18
|
pychemstation/generated/__init__.py,sha256=GAoZFAYbPVEJDkcOw3e1rgOqd7TCW0HyKNPM8OMehMg,1005
|
19
19
|
pychemstation/generated/dad_method.py,sha256=0W8Z5WDtF5jpIcudMqb7XrkTnR2EGg_QOCsHRFQ0rmM,8402
|
20
20
|
pychemstation/generated/pump_method.py,sha256=sUhE2Oo00nzVcoONtq3EMWsN4wLSryXbG8f3EeViWKg,12174
|
21
21
|
pychemstation/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
22
|
-
pychemstation/utils/chromatogram.py,sha256=
|
22
|
+
pychemstation/utils/chromatogram.py,sha256=RiKWQG2FIlDzddhgABV-WIJg_BsCTL_wPfyYGikyxoM,3097
|
23
23
|
pychemstation/utils/macro.py,sha256=BAIcE_dppNffwrSqGq8gh0ccE9YAJfQFQZHXJgA1WtA,2586
|
24
24
|
pychemstation/utils/method_types.py,sha256=YngbyHg96JSFnvhm5Zd7wJvLTQPPQsLbvbyz3HlGLYY,862
|
25
25
|
pychemstation/utils/parsing.py,sha256=bnFIsZZwFy9NKzVUf517yN-ogzQbm0hp_aho3KUD6Is,9317
|
@@ -28,12 +28,12 @@ pychemstation/utils/table_types.py,sha256=cN51Ry2pammDdk85cabVH3qkchjKKIzZfAH87P
|
|
28
28
|
pychemstation/utils/tray_types.py,sha256=UUDED-IAf-8FmPVZezuWSiIQE_HgiZQMV2sTqu4oZw8,177
|
29
29
|
tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
30
30
|
tests/constants.py,sha256=lLwT_QaVriivL5llkul6RxXxPriwUp1E-Y3G9fejvbo,2092
|
31
|
-
tests/test_comb.py,sha256=
|
31
|
+
tests/test_comb.py,sha256=CF6nSxUMBJeUjA-IfgPcBGV5oIG4aH1-RA26oIATa-s,5640
|
32
32
|
tests/test_comm.py,sha256=1ZZd0UrIBOKe91wzA-XI-gSRgXmId9mLWYSMeche82Y,2973
|
33
33
|
tests/test_method.py,sha256=uCPpZVYKPz1CNWwhmBo_8TH0ku2V0ZpDZJj3f8iINB4,2440
|
34
34
|
tests/test_sequence.py,sha256=yIQGhUTehtHz6D1ai5W6AlP0zes2icF0VdQ0IGJ2CbQ,4901
|
35
|
-
pychemstation-0.5.
|
36
|
-
pychemstation-0.5.
|
37
|
-
pychemstation-0.5.
|
38
|
-
pychemstation-0.5.
|
39
|
-
pychemstation-0.5.
|
35
|
+
pychemstation-0.5.6.dev1.dist-info/LICENSE,sha256=9bdF75gIf1MecZ7oymqWgJREVz7McXPG-mjqrTmzzD8,18658
|
36
|
+
pychemstation-0.5.6.dev1.dist-info/METADATA,sha256=7Pj5MObTqRmX3B19nhA70BzBRyHSA7bDku7O1-D89lE,4312
|
37
|
+
pychemstation-0.5.6.dev1.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
38
|
+
pychemstation-0.5.6.dev1.dist-info/top_level.txt,sha256=zXfKu_4nYWwPHo3OsuhshMNC3SPkcoTGCyODjURaghY,20
|
39
|
+
pychemstation-0.5.6.dev1.dist-info/RECORD,,
|
tests/test_comb.py
CHANGED
@@ -28,14 +28,14 @@ class TestCombinations(unittest.TestCase):
|
|
28
28
|
first_row=HPLCMethodParams(
|
29
29
|
organic_modifier=5,
|
30
30
|
flow=0.65,
|
31
|
-
maximum_run_time=
|
31
|
+
maximum_run_time=1),
|
32
32
|
subsequent_rows=[
|
33
33
|
TimeTableEntry(
|
34
34
|
start_time=0.10,
|
35
35
|
organic_modifer=5,
|
36
36
|
flow=0.34),
|
37
37
|
TimeTableEntry(
|
38
|
-
start_time=
|
38
|
+
start_time=0.5,
|
39
39
|
organic_modifer=98,
|
40
40
|
flow=0.55)])
|
41
41
|
self.hplc_controller.edit_method(rand_method, save=True)
|
File without changes
|
File without changes
|
File without changes
|