pychemstation 0.5.3.dev1__tar.gz → 0.5.5__tar.gz
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-0.5.3.dev1 → pychemstation-0.5.5}/PKG-INFO +12 -9
- {pychemstation-0.5.3.dev1 → pychemstation-0.5.5}/README.md +10 -8
- {pychemstation-0.5.3.dev1 → pychemstation-0.5.5}/pychemstation/control/__init__.py +0 -1
- {pychemstation-0.5.3.dev1/pychemstation/control/table → pychemstation-0.5.5/pychemstation/control/controllers}/__init__.py +1 -0
- {pychemstation-0.5.3.dev1/pychemstation/control → pychemstation-0.5.5/pychemstation/control/controllers}/comm.py +11 -7
- {pychemstation-0.5.3.dev1/pychemstation/control/table → pychemstation-0.5.5/pychemstation/control/controllers}/method.py +6 -6
- {pychemstation-0.5.3.dev1/pychemstation/control/table → pychemstation-0.5.5/pychemstation/control/controllers}/sequence.py +44 -50
- {pychemstation-0.5.3.dev1/pychemstation/control/table → pychemstation-0.5.5/pychemstation/control/controllers}/table_controller.py +36 -12
- {pychemstation-0.5.3.dev1 → pychemstation-0.5.5}/pychemstation/control/hplc.py +10 -11
- {pychemstation-0.5.3.dev1 → pychemstation-0.5.5}/pychemstation/utils/chromatogram.py +7 -26
- {pychemstation-0.5.3.dev1 → pychemstation-0.5.5}/pychemstation/utils/table_types.py +1 -0
- {pychemstation-0.5.3.dev1 → pychemstation-0.5.5}/pychemstation.egg-info/PKG-INFO +12 -9
- {pychemstation-0.5.3.dev1 → pychemstation-0.5.5}/pychemstation.egg-info/SOURCES.txt +5 -5
- {pychemstation-0.5.3.dev1 → pychemstation-0.5.5}/pychemstation.egg-info/requires.txt +1 -0
- {pychemstation-0.5.3.dev1 → pychemstation-0.5.5}/setup.py +6 -5
- {pychemstation-0.5.3.dev1 → pychemstation-0.5.5}/tests/constants.py +4 -4
- pychemstation-0.5.5/tests/test_comb.py +143 -0
- {pychemstation-0.5.3.dev1 → pychemstation-0.5.5}/tests/test_sequence.py +48 -0
- pychemstation-0.5.3.dev1/tests/test_comb.py +0 -129
- {pychemstation-0.5.3.dev1 → pychemstation-0.5.5}/LICENSE +0 -0
- {pychemstation-0.5.3.dev1 → pychemstation-0.5.5}/pychemstation/__init__.py +0 -0
- {pychemstation-0.5.3.dev1 → pychemstation-0.5.5}/pychemstation/analysis/__init__.py +0 -0
- {pychemstation-0.5.3.dev1 → pychemstation-0.5.5}/pychemstation/analysis/base_spectrum.py +0 -0
- {pychemstation-0.5.3.dev1 → pychemstation-0.5.5}/pychemstation/analysis/spec_utils.py +0 -0
- {pychemstation-0.5.3.dev1 → pychemstation-0.5.5}/pychemstation/analysis/utils.py +0 -0
- {pychemstation-0.5.3.dev1 → pychemstation-0.5.5}/pychemstation/generated/__init__.py +0 -0
- {pychemstation-0.5.3.dev1 → pychemstation-0.5.5}/pychemstation/generated/dad_method.py +0 -0
- {pychemstation-0.5.3.dev1 → pychemstation-0.5.5}/pychemstation/generated/pump_method.py +0 -0
- {pychemstation-0.5.3.dev1 → pychemstation-0.5.5}/pychemstation/utils/__init__.py +0 -0
- {pychemstation-0.5.3.dev1 → pychemstation-0.5.5}/pychemstation/utils/macro.py +0 -0
- {pychemstation-0.5.3.dev1 → pychemstation-0.5.5}/pychemstation/utils/method_types.py +0 -0
- {pychemstation-0.5.3.dev1 → pychemstation-0.5.5}/pychemstation/utils/parsing.py +0 -0
- {pychemstation-0.5.3.dev1 → pychemstation-0.5.5}/pychemstation/utils/sequence_types.py +0 -0
- {pychemstation-0.5.3.dev1 → pychemstation-0.5.5}/pychemstation/utils/tray_types.py +0 -0
- {pychemstation-0.5.3.dev1 → pychemstation-0.5.5}/pychemstation.egg-info/dependency_links.txt +0 -0
- {pychemstation-0.5.3.dev1 → pychemstation-0.5.5}/pychemstation.egg-info/top_level.txt +0 -0
- {pychemstation-0.5.3.dev1 → pychemstation-0.5.5}/pyproject.toml +0 -0
- {pychemstation-0.5.3.dev1 → pychemstation-0.5.5}/setup.cfg +0 -0
- {pychemstation-0.5.3.dev1 → pychemstation-0.5.5}/tests/__init__.py +0 -0
- {pychemstation-0.5.3.dev1 → pychemstation-0.5.5}/tests/test_comm.py +0 -0
- {pychemstation-0.5.3.dev1 → pychemstation-0.5.5}/tests/test_method.py +0 -0
@@ -1,8 +1,8 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: pychemstation
|
3
|
-
Version: 0.5.
|
3
|
+
Version: 0.5.5
|
4
4
|
Summary: Library to interact with Chemstation software, primarily used in Hein lab
|
5
|
-
Home-page: https://gitlab.com/heingroup/pychemstation
|
5
|
+
Home-page: https://gitlab.com/heingroup/device-api/pychemstation
|
6
6
|
Author: Lucy Hao
|
7
7
|
Author-email: lhao03@student.ubc.ca
|
8
8
|
Classifier: Programming Language :: Python :: 3
|
@@ -12,6 +12,7 @@ Description-Content-Type: text/markdown
|
|
12
12
|
License-File: LICENSE
|
13
13
|
Requires-Dist: polling
|
14
14
|
Requires-Dist: seabreeze
|
15
|
+
Requires-Dist: xsdata
|
15
16
|
|
16
17
|
# Agilent HPLC Macro Control
|
17
18
|
|
@@ -40,7 +41,7 @@ pip install pychemstation
|
|
40
41
|
where you will put your
|
41
42
|
MACRO file(s).
|
42
43
|
3. Download the [
|
43
|
-
`hplc_talk.mac`](https://
|
44
|
+
`hplc_talk.mac`](https://gitlab.com/heingroup/device-api/pychemstation/-/blob/main/tests/hplc_talk.mac).
|
44
45
|
- On line 69, change the path name up to `\cmd` and `\reply`. For instance, you should have:
|
45
46
|
`MonitorFile "[my path]\cmd", "[my path]\reply"`
|
46
47
|
- and then add this file to the folder from the previous step.
|
@@ -77,13 +78,12 @@ hplc_controller = HPLCController(data_dir=DATA_DIR,
|
|
77
78
|
hplc_controller.preprun()
|
78
79
|
hplc_controller.switch_method(method_name=DEFAULT_METHOD)
|
79
80
|
hplc_controller.run_method(experiment_name="Run 10")
|
80
|
-
|
81
|
+
chrom = hplc_controller.get_last_run_method_data()
|
81
82
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
chromatogram_data.to_csv("Run 10.csv", index=False)
|
83
|
+
# afterwards, save, analyze or plot the data!
|
84
|
+
values = {"x": chrom.A.x, "y": chrom.A.y}
|
85
|
+
chromatogram_data = pd.DataFrame.from_dict(values)
|
86
|
+
chromatogram_data.to_csv("Run 10.csv", index=False)
|
87
87
|
```
|
88
88
|
|
89
89
|
## Adding your own MACROs
|
@@ -102,3 +102,6 @@ Lucy Hao
|
|
102
102
|
|
103
103
|
- Adapted from [**AnalyticalLabware**](https://github.com/croningp/analyticallabware), created by members in the Cronin
|
104
104
|
Group. Copyright © Cronin Group, used under the [CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/) license.
|
105
|
+
- Adapted from the [MACROS](https://github.com/Bourne-Group/HPLCMethodOptimisationGUI)
|
106
|
+
used in [**Operator-free HPLC automated method development guided by Bayesian optimization**](https://pubs.rsc.org/en/content/articlelanding/2024/dd/d4dd00062e),
|
107
|
+
created by members in the Bourne Group. Copyright © Bourne Group, used under the [MIT](https://opensource.org/license/mit) license.
|
@@ -25,7 +25,7 @@ pip install pychemstation
|
|
25
25
|
where you will put your
|
26
26
|
MACRO file(s).
|
27
27
|
3. Download the [
|
28
|
-
`hplc_talk.mac`](https://
|
28
|
+
`hplc_talk.mac`](https://gitlab.com/heingroup/device-api/pychemstation/-/blob/main/tests/hplc_talk.mac).
|
29
29
|
- On line 69, change the path name up to `\cmd` and `\reply`. For instance, you should have:
|
30
30
|
`MonitorFile "[my path]\cmd", "[my path]\reply"`
|
31
31
|
- and then add this file to the folder from the previous step.
|
@@ -62,13 +62,12 @@ hplc_controller = HPLCController(data_dir=DATA_DIR,
|
|
62
62
|
hplc_controller.preprun()
|
63
63
|
hplc_controller.switch_method(method_name=DEFAULT_METHOD)
|
64
64
|
hplc_controller.run_method(experiment_name="Run 10")
|
65
|
-
|
65
|
+
chrom = hplc_controller.get_last_run_method_data()
|
66
66
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
chromatogram_data.to_csv("Run 10.csv", index=False)
|
67
|
+
# afterwards, save, analyze or plot the data!
|
68
|
+
values = {"x": chrom.A.x, "y": chrom.A.y}
|
69
|
+
chromatogram_data = pd.DataFrame.from_dict(values)
|
70
|
+
chromatogram_data.to_csv("Run 10.csv", index=False)
|
72
71
|
```
|
73
72
|
|
74
73
|
## Adding your own MACROs
|
@@ -86,4 +85,7 @@ our [GitLab](https://gitlab.com/heingroup/device-api/pychemstation)!
|
|
86
85
|
Lucy Hao
|
87
86
|
|
88
87
|
- Adapted from [**AnalyticalLabware**](https://github.com/croningp/analyticallabware), created by members in the Cronin
|
89
|
-
Group. Copyright © Cronin Group, used under the [CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/) license.
|
88
|
+
Group. Copyright © Cronin Group, used under the [CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/) license.
|
89
|
+
- Adapted from the [MACROS](https://github.com/Bourne-Group/HPLCMethodOptimisationGUI)
|
90
|
+
used in [**Operator-free HPLC automated method development guided by Bayesian optimization**](https://pubs.rsc.org/en/content/articlelanding/2024/dd/d4dd00062e),
|
91
|
+
created by members in the Bourne Group. Copyright © Bourne Group, used under the [MIT](https://opensource.org/license/mit) license.
|
@@ -14,8 +14,8 @@ import os
|
|
14
14
|
import time
|
15
15
|
|
16
16
|
from result import Result, Ok, Err
|
17
|
-
|
18
|
-
from
|
17
|
+
|
18
|
+
from ...utils.macro import *
|
19
19
|
|
20
20
|
|
21
21
|
class CommunicationController:
|
@@ -86,17 +86,18 @@ class CommunicationController:
|
|
86
86
|
|
87
87
|
def set_status(self):
|
88
88
|
"""Updates current status of HPLC machine"""
|
89
|
-
self._most_recent_hplc_status = self.get_status()
|
89
|
+
self._most_recent_hplc_status = self.get_status()
|
90
90
|
|
91
|
-
def check_if_running(self
|
91
|
+
def check_if_running(self) -> bool:
|
92
92
|
"""Checks if HPLC machine is in an available state, meaning a state that data is not being written.
|
93
93
|
|
94
94
|
:return: whether the HPLC machine is in a safe state to retrieve data back."""
|
95
95
|
self.set_status()
|
96
|
-
file_exists = os.path.exists(data_path)
|
97
96
|
hplc_avail = isinstance(self._most_recent_hplc_status, HPLCAvailStatus)
|
98
|
-
|
99
|
-
|
97
|
+
time.sleep(30)
|
98
|
+
self.set_status()
|
99
|
+
hplc_actually_avail = isinstance(self._most_recent_hplc_status, HPLCAvailStatus)
|
100
|
+
return hplc_avail and hplc_actually_avail
|
100
101
|
|
101
102
|
def _send(self, cmd: str, cmd_no: int, num_attempts=5) -> None:
|
102
103
|
"""Low-level execution primitive. Sends a command string to HPLC.
|
@@ -170,6 +171,9 @@ class CommunicationController:
|
|
170
171
|
cmd_to_send: str = cmd.value if isinstance(cmd, Command) else cmd
|
171
172
|
self.cmd_no += 1
|
172
173
|
self._send(cmd_to_send, self.cmd_no)
|
174
|
+
f = open("out.txt", "a")
|
175
|
+
f.write(cmd_to_send + "\n")
|
176
|
+
f.close()
|
173
177
|
|
174
178
|
def receive(self) -> Result[Response, str]:
|
175
179
|
"""Returns messages received in reply file.
|
@@ -1,13 +1,13 @@
|
|
1
1
|
import os
|
2
2
|
import time
|
3
|
-
from typing import Optional
|
3
|
+
from typing import Optional
|
4
4
|
|
5
5
|
from xsdata.formats.dataclass.parsers import XmlParser
|
6
6
|
|
7
|
-
from
|
8
|
-
from ...control.
|
7
|
+
from ...control.controllers.table_controller import TableController
|
8
|
+
from ...control.controllers.comm import CommunicationController
|
9
9
|
from ...generated import PumpMethod, DadMethod, SolventElement
|
10
|
-
from ...utils.chromatogram import TIME_FORMAT,
|
10
|
+
from ...utils.chromatogram import TIME_FORMAT, AgilentChannelChromatogramData
|
11
11
|
from ...utils.macro import Command
|
12
12
|
from ...utils.method_types import PType, TimeTableEntry, Param, MethodTimetable, HPLCMethodParams
|
13
13
|
from ...utils.table_types import RegisterFlag, TableOperation, Table
|
@@ -269,6 +269,6 @@ class MethodController(TableController):
|
|
269
269
|
def retrieve_recent_data_files(self) -> str:
|
270
270
|
return self.data_files[-1]
|
271
271
|
|
272
|
-
def get_data(self) ->
|
272
|
+
def get_data(self) -> AgilentChannelChromatogramData:
|
273
273
|
self.get_spectrum(self.data_files[-1])
|
274
|
-
return self.spectra
|
274
|
+
return AgilentChannelChromatogramData(**self.spectra)
|
@@ -1,17 +1,12 @@
|
|
1
|
-
from typing import Any
|
2
|
-
|
3
|
-
from copy import deepcopy
|
4
|
-
|
5
1
|
import os
|
6
2
|
import time
|
7
3
|
|
8
|
-
from .table_controller import TableController
|
9
|
-
from ...control import CommunicationController
|
10
|
-
from ...utils.chromatogram import SEQUENCE_TIME_FORMAT,
|
4
|
+
from ...control.controllers.table_controller import TableController
|
5
|
+
from ...control.controllers.comm import CommunicationController
|
6
|
+
from ...utils.chromatogram import SEQUENCE_TIME_FORMAT, AgilentChannelChromatogramData
|
11
7
|
from ...utils.macro import Command
|
12
8
|
from ...utils.sequence_types import SequenceTable, SequenceEntry, SequenceDataFiles, InjectionSource, SampleType
|
13
9
|
from ...utils.table_types import TableOperation, RegisterFlag, Table
|
14
|
-
from ...utils.tray_types import TenColumn
|
15
10
|
|
16
11
|
|
17
12
|
class SequenceController(TableController):
|
@@ -30,7 +25,7 @@ class SequenceController(TableController):
|
|
30
25
|
|
31
26
|
if rows.is_ok() and seq_name.is_ok():
|
32
27
|
return SequenceTable(
|
33
|
-
name=seq_name.ok_value.
|
28
|
+
name=seq_name.ok_value.string_response.partition(".S")[0],
|
34
29
|
rows=[self.get_row(r + 1) for r in range(int(rows.ok_value.num_response))])
|
35
30
|
raise RuntimeError(rows.err_value)
|
36
31
|
|
@@ -73,34 +68,25 @@ class SequenceController(TableController):
|
|
73
68
|
|
74
69
|
:param sequence_table:
|
75
70
|
"""
|
76
|
-
|
77
|
-
self.
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
self.add_row()
|
87
|
-
self.sleep(1)
|
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))
|
88
81
|
self.send(Command.SAVE_SEQUENCE_CMD)
|
89
|
-
|
90
|
-
self.send(Command.
|
82
|
+
existing_row_num = self.get_num_rows().ok_value.num_response
|
83
|
+
self.send(Command.SWITCH_SEQUENCE_CMD)
|
84
|
+
|
91
85
|
for i, row in enumerate(sequence_table.rows):
|
92
86
|
self.edit_row(row=row, row_num=i + 1)
|
93
87
|
self.sleep(1)
|
94
88
|
self.send(Command.SAVE_SEQUENCE_CMD)
|
95
|
-
|
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)
|
89
|
+
self.send(Command.SWITCH_SEQUENCE_CMD)
|
104
90
|
|
105
91
|
def edit_row(self, row: SequenceEntry, row_num: int):
|
106
92
|
"""
|
@@ -120,13 +106,16 @@ class SequenceController(TableController):
|
|
120
106
|
table_name = self.table.name
|
121
107
|
|
122
108
|
if row.vial_location:
|
109
|
+
loc = row.vial_location
|
110
|
+
if isinstance(row.vial_location, InjectionSource):
|
111
|
+
loc = row.vial_location.value
|
123
112
|
self.sleepy_send(TableOperation.EDIT_ROW_VAL.value.format(register=table_register,
|
124
113
|
table_name=table_name,
|
125
114
|
row=row_num,
|
126
115
|
col_name=RegisterFlag.VIAL_LOCATION,
|
127
|
-
val=
|
116
|
+
val=loc))
|
128
117
|
if row.method:
|
129
|
-
possible_path = os.path.join(self.method_dir, row.method)
|
118
|
+
possible_path = os.path.join(self.method_dir, row.method) + ".M\\"
|
130
119
|
method = row.method
|
131
120
|
if os.path.exists(possible_path):
|
132
121
|
method = os.path.join(self.method_dir, row.method)
|
@@ -177,23 +166,22 @@ class SequenceController(TableController):
|
|
177
166
|
|
178
167
|
self.send(Command.SAVE_SEQUENCE_CMD)
|
179
168
|
|
180
|
-
def run(self
|
169
|
+
def run(self):
|
181
170
|
"""
|
182
171
|
Starts the currently loaded sequence, storing data
|
183
172
|
under the <data_dir>/<sequence table name> folder.
|
184
173
|
Device must be ready.
|
185
|
-
|
186
|
-
:param sequence_table:
|
187
174
|
"""
|
188
175
|
timestamp = time.strftime(SEQUENCE_TIME_FORMAT)
|
176
|
+
seq_table = self.load()
|
189
177
|
self.send(Command.RUN_SEQUENCE_CMD.value)
|
190
178
|
|
191
179
|
if self.check_hplc_is_running():
|
192
|
-
folder_name = f"{
|
180
|
+
folder_name = f"{seq_table.name} {timestamp}"
|
193
181
|
self.data_files.append(SequenceDataFiles(dir=folder_name,
|
194
|
-
sequence_name=
|
182
|
+
sequence_name=seq_table.name))
|
195
183
|
|
196
|
-
run_completed = self.check_hplc_done_running()
|
184
|
+
run_completed = self.check_hplc_done_running(sequence=seq_table)
|
197
185
|
|
198
186
|
if run_completed.is_ok():
|
199
187
|
self.data_files[-1].dir = run_completed.value
|
@@ -202,16 +190,22 @@ class SequenceController(TableController):
|
|
202
190
|
|
203
191
|
def retrieve_recent_data_files(self):
|
204
192
|
sequence_data_files: SequenceDataFiles = self.data_files[-1]
|
205
|
-
return
|
193
|
+
return sequence_data_files.dir
|
206
194
|
|
207
|
-
def get_data(self) -> list[
|
208
|
-
|
195
|
+
def get_data(self) -> list[AgilentChannelChromatogramData]:
|
196
|
+
parent_dir = self.data_files[-1].dir
|
209
197
|
subdirs = [x[0] for x in os.walk(self.data_dir)]
|
210
|
-
potential_folders = sorted(list(filter(lambda d:
|
211
|
-
self.data_files[-1].child_dirs = potential_folders
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
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"]))
|
217
211
|
return spectra
|
@@ -6,16 +6,17 @@ Authors: Lucy Hao
|
|
6
6
|
|
7
7
|
import abc
|
8
8
|
import os
|
9
|
+
import time
|
9
10
|
from typing import Union, Optional
|
10
11
|
|
11
12
|
import polling
|
12
13
|
from result import Result, Ok, Err
|
13
14
|
|
14
|
-
from ...control import CommunicationController
|
15
|
-
from ...utils.chromatogram import AgilentHPLCChromatogram
|
15
|
+
from ...control.controllers.comm import CommunicationController
|
16
|
+
from ...utils.chromatogram import AgilentHPLCChromatogram, AgilentChannelChromatogramData
|
16
17
|
from ...utils.macro import Command, HPLCRunningStatus, Response
|
17
18
|
from ...utils.method_types import MethodTimetable
|
18
|
-
from ...utils.sequence_types import SequenceDataFiles
|
19
|
+
from ...utils.sequence_types import SequenceDataFiles, SequenceTable
|
19
20
|
from ...utils.table_types import Table, TableOperation, RegisterFlag
|
20
21
|
|
21
22
|
|
@@ -82,6 +83,11 @@ class TableController(abc.ABC):
|
|
82
83
|
def get_row(self, row: int):
|
83
84
|
pass
|
84
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
|
+
|
85
91
|
def add_row(self):
|
86
92
|
"""
|
87
93
|
Adds a row to the provided table for currently loaded method or sequence.
|
@@ -124,7 +130,7 @@ class TableController(abc.ABC):
|
|
124
130
|
res = self.controller.receive()
|
125
131
|
|
126
132
|
if res.is_ok():
|
127
|
-
self.send("Sleep 1")
|
133
|
+
self.send("Sleep 0.1")
|
128
134
|
self.send('Print Rows')
|
129
135
|
return res
|
130
136
|
else:
|
@@ -137,24 +143,42 @@ class TableController(abc.ABC):
|
|
137
143
|
max_tries=10)
|
138
144
|
return started_running
|
139
145
|
|
140
|
-
def check_hplc_done_running(self,
|
146
|
+
def check_hplc_done_running(self,
|
147
|
+
method: Optional[MethodTimetable] = None,
|
148
|
+
sequence: Optional[SequenceTable] = None) -> Result[str, str]:
|
141
149
|
"""
|
142
150
|
Checks if ChemStation has finished running and can read data back
|
143
151
|
|
144
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
|
145
153
|
:return: Return True if data can be read back, else False.
|
146
154
|
"""
|
147
|
-
timeout = 10 * 60
|
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
|
+
|
148
161
|
most_recent_folder = self.retrieve_recent_data_files()
|
149
162
|
finished_run = polling.poll(
|
150
|
-
lambda: self.controller.check_if_running(
|
163
|
+
lambda: self.controller.check_if_running(),
|
151
164
|
timeout=timeout,
|
152
|
-
step=
|
165
|
+
step=60
|
153
166
|
)
|
167
|
+
|
154
168
|
if finished_run:
|
155
|
-
|
156
|
-
|
157
|
-
|
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)
|
158
182
|
else:
|
159
183
|
return Err("Run did not complete as expected")
|
160
184
|
|
@@ -163,7 +187,7 @@ class TableController(abc.ABC):
|
|
163
187
|
pass
|
164
188
|
|
165
189
|
@abc.abstractmethod
|
166
|
-
def get_data(self) ->
|
190
|
+
def get_data(self) -> Union[list[AgilentChannelChromatogramData], AgilentChannelChromatogramData]:
|
167
191
|
pass
|
168
192
|
|
169
193
|
def get_spectrum(self, data_file: str):
|
@@ -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 ..
|
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
|
-
:
|
69
|
-
:
|
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
|
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
|
99
|
+
:param sequence_name:
|
101
100
|
"""
|
102
|
-
self.sequence_controller.run(
|
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
|
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) ->
|
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[
|
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
|
"""
|
@@ -1,17 +1,14 @@
|
|
1
1
|
"""Module for HPLC chromatogram data loading and manipulating"""
|
2
2
|
|
3
3
|
import os
|
4
|
-
import logging
|
5
4
|
import time
|
5
|
+
from dataclasses import dataclass
|
6
6
|
|
7
7
|
import numpy as np
|
8
8
|
|
9
9
|
from .parsing import CHFile
|
10
10
|
from ..analysis import AbstractSpectrum
|
11
11
|
|
12
|
-
# Chemstation data path
|
13
|
-
DATA_DIR = r"C:\Chem32\1\Data"
|
14
|
-
|
15
12
|
# standard filenames for spectral data
|
16
13
|
CHANNELS = {"A": "01", "B": "02", "C": "03", "D": "04"}
|
17
14
|
|
@@ -105,26 +102,10 @@ class AgilentHPLCChromatogram(AbstractSpectrum):
|
|
105
102
|
np.savez_compressed(npz_file, times=data.times, values=data.values)
|
106
103
|
return np.array(data.times), np.array(data.values)
|
107
104
|
|
108
|
-
def extract_peakarea(self, experiment_dir: str):
|
109
|
-
"""
|
110
|
-
Reads processed data from Chemstation report files.
|
111
105
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
# return data
|
119
|
-
pass
|
120
|
-
|
121
|
-
def default_processing(self):
|
122
|
-
"""
|
123
|
-
Processes the chromatogram in place.
|
124
|
-
"""
|
125
|
-
# trim first 5 min and last 3 min of run
|
126
|
-
self.trim(5, 25)
|
127
|
-
# parameters found to work best for chromatogram data
|
128
|
-
self.correct_baseline(lmbd=1e5, p=0.0001, n_iter=10)
|
129
|
-
# get all peaks in processed chromatogram
|
130
|
-
self.find_peaks()
|
106
|
+
@dataclass
|
107
|
+
class AgilentChannelChromatogramData:
|
108
|
+
A: AgilentHPLCChromatogram
|
109
|
+
B: AgilentHPLCChromatogram
|
110
|
+
C: AgilentHPLCChromatogram
|
111
|
+
D: AgilentHPLCChromatogram
|
@@ -9,6 +9,7 @@ class TableOperation(Enum):
|
|
9
9
|
DELETE_TABLE = 'DelTab {register}, "{table_name}"'
|
10
10
|
CREATE_TABLE = 'NewTab {register}, "{table_name}"'
|
11
11
|
NEW_ROW = 'InsTabRow {register}, "{table_name}"'
|
12
|
+
DELETE_ROW = 'DelTabRow {register}, "{table_name}", {row}'
|
12
13
|
EDIT_ROW_VAL = 'SetTabVal "{register}", "{table_name}", {row}, "{col_name}", {val}'
|
13
14
|
EDIT_ROW_TEXT = 'SetTabText "{register}", "{table_name}", {row}, "{col_name}", "{val}"'
|
14
15
|
GET_ROW_VAL = 'TabVal("{register}", "{table_name}", {row}, "{col_name}")'
|
@@ -1,8 +1,8 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: pychemstation
|
3
|
-
Version: 0.5.
|
3
|
+
Version: 0.5.5
|
4
4
|
Summary: Library to interact with Chemstation software, primarily used in Hein lab
|
5
|
-
Home-page: https://gitlab.com/heingroup/pychemstation
|
5
|
+
Home-page: https://gitlab.com/heingroup/device-api/pychemstation
|
6
6
|
Author: Lucy Hao
|
7
7
|
Author-email: lhao03@student.ubc.ca
|
8
8
|
Classifier: Programming Language :: Python :: 3
|
@@ -12,6 +12,7 @@ Description-Content-Type: text/markdown
|
|
12
12
|
License-File: LICENSE
|
13
13
|
Requires-Dist: polling
|
14
14
|
Requires-Dist: seabreeze
|
15
|
+
Requires-Dist: xsdata
|
15
16
|
|
16
17
|
# Agilent HPLC Macro Control
|
17
18
|
|
@@ -40,7 +41,7 @@ pip install pychemstation
|
|
40
41
|
where you will put your
|
41
42
|
MACRO file(s).
|
42
43
|
3. Download the [
|
43
|
-
`hplc_talk.mac`](https://
|
44
|
+
`hplc_talk.mac`](https://gitlab.com/heingroup/device-api/pychemstation/-/blob/main/tests/hplc_talk.mac).
|
44
45
|
- On line 69, change the path name up to `\cmd` and `\reply`. For instance, you should have:
|
45
46
|
`MonitorFile "[my path]\cmd", "[my path]\reply"`
|
46
47
|
- and then add this file to the folder from the previous step.
|
@@ -77,13 +78,12 @@ hplc_controller = HPLCController(data_dir=DATA_DIR,
|
|
77
78
|
hplc_controller.preprun()
|
78
79
|
hplc_controller.switch_method(method_name=DEFAULT_METHOD)
|
79
80
|
hplc_controller.run_method(experiment_name="Run 10")
|
80
|
-
|
81
|
+
chrom = hplc_controller.get_last_run_method_data()
|
81
82
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
chromatogram_data.to_csv("Run 10.csv", index=False)
|
83
|
+
# afterwards, save, analyze or plot the data!
|
84
|
+
values = {"x": chrom.A.x, "y": chrom.A.y}
|
85
|
+
chromatogram_data = pd.DataFrame.from_dict(values)
|
86
|
+
chromatogram_data.to_csv("Run 10.csv", index=False)
|
87
87
|
```
|
88
88
|
|
89
89
|
## Adding your own MACROs
|
@@ -102,3 +102,6 @@ Lucy Hao
|
|
102
102
|
|
103
103
|
- Adapted from [**AnalyticalLabware**](https://github.com/croningp/analyticallabware), created by members in the Cronin
|
104
104
|
Group. Copyright © Cronin Group, used under the [CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/) license.
|
105
|
+
- Adapted from the [MACROS](https://github.com/Bourne-Group/HPLCMethodOptimisationGUI)
|
106
|
+
used in [**Operator-free HPLC automated method development guided by Bayesian optimization**](https://pubs.rsc.org/en/content/articlelanding/2024/dd/d4dd00062e),
|
107
|
+
created by members in the Bourne Group. Copyright © Bourne Group, used under the [MIT](https://opensource.org/license/mit) license.
|
@@ -13,12 +13,12 @@ pychemstation/analysis/base_spectrum.py
|
|
13
13
|
pychemstation/analysis/spec_utils.py
|
14
14
|
pychemstation/analysis/utils.py
|
15
15
|
pychemstation/control/__init__.py
|
16
|
-
pychemstation/control/comm.py
|
17
16
|
pychemstation/control/hplc.py
|
18
|
-
pychemstation/control/
|
19
|
-
pychemstation/control/
|
20
|
-
pychemstation/control/
|
21
|
-
pychemstation/control/
|
17
|
+
pychemstation/control/controllers/__init__.py
|
18
|
+
pychemstation/control/controllers/comm.py
|
19
|
+
pychemstation/control/controllers/method.py
|
20
|
+
pychemstation/control/controllers/sequence.py
|
21
|
+
pychemstation/control/controllers/table_controller.py
|
22
22
|
pychemstation/generated/__init__.py
|
23
23
|
pychemstation/generated/dad_method.py
|
24
24
|
pychemstation/generated/pump_method.py
|
@@ -5,21 +5,22 @@ with open("README.md", "r") as fh:
|
|
5
5
|
|
6
6
|
setuptools.setup(
|
7
7
|
name="pychemstation",
|
8
|
-
version="0.5.
|
8
|
+
version="0.5.5",
|
9
9
|
author="Lucy Hao",
|
10
10
|
author_email="lhao03@student.ubc.ca",
|
11
11
|
description="Library to interact with Chemstation software, primarily used in Hein lab",
|
12
12
|
long_description=long_description,
|
13
13
|
long_description_content_type="text/markdown",
|
14
|
-
url="https://gitlab.com/heingroup/pychemstation",
|
14
|
+
url="https://gitlab.com/heingroup/device-api/pychemstation",
|
15
15
|
packages=setuptools.find_packages(),
|
16
16
|
install_requires=[
|
17
|
-
|
18
|
-
|
17
|
+
'polling',
|
18
|
+
'seabreeze',
|
19
|
+
'xsdata'
|
19
20
|
],
|
20
21
|
classifiers=[
|
21
22
|
"Programming Language :: Python :: 3",
|
22
23
|
"License :: OSI Approved :: MIT License",
|
23
24
|
"Operating System :: OS Independent",
|
24
25
|
],
|
25
|
-
)
|
26
|
+
)
|
@@ -4,7 +4,7 @@ from pychemstation.utils.method_types import *
|
|
4
4
|
from pychemstation.utils.sequence_types import *
|
5
5
|
|
6
6
|
DEFAULT_METHOD = "GENERAL-POROSHELL-OPT"
|
7
|
-
DEFAULT_SEQUENCE = "
|
7
|
+
DEFAULT_SEQUENCE = "LLETest"
|
8
8
|
|
9
9
|
# CONSTANTS: paths only work in Hein group HPLC machine in room 242
|
10
10
|
DEFAULT_COMMAND_PATH = "C:\\Users\\User\\Desktop\\Lucy\\"
|
@@ -20,8 +20,8 @@ HEIN_LAB_CONSTANTS = [DEFAULT_COMMAND_PATH,
|
|
20
20
|
# these CONSTANTS work in rm 254
|
21
21
|
DEFAULT_COMMAND_PATH_254 = "D:\\\git_repositories\\\hplc_comm\\"
|
22
22
|
DEFAULT_METHOD_DIR_254 = "D:\\Chemstation\\1\\Methods\\"
|
23
|
-
DATA_DIR_254 = "D:\\Chemstation\\1\\Data"
|
24
|
-
SEQUENCE_DIR_254 = "C:\\1\\Sequence"
|
23
|
+
DATA_DIR_254 = "D:\\Chemstation\\1\\Data\\2024-12\\"
|
24
|
+
SEQUENCE_DIR_254 = "C:\\1\\Sequence\\"
|
25
25
|
|
26
26
|
HEIN_LAB_CONSTANTS_254 = [DEFAULT_COMMAND_PATH_254,
|
27
27
|
DEFAULT_METHOD_DIR_254,
|
@@ -42,7 +42,7 @@ def gen_rand_method():
|
|
42
42
|
return MethodTimetable(
|
43
43
|
first_row=HPLCMethodParams(
|
44
44
|
organic_modifier=org_modifier,
|
45
|
-
flow=random.random(),
|
45
|
+
flow=round(random.random(), 2),
|
46
46
|
maximum_run_time=max_run_time),
|
47
47
|
subsequent_rows=[
|
48
48
|
TimeTableEntry(
|
@@ -0,0 +1,143 @@
|
|
1
|
+
import os
|
2
|
+
|
3
|
+
import unittest
|
4
|
+
|
5
|
+
from pychemstation.control import HPLCController
|
6
|
+
from tests.constants import *
|
7
|
+
|
8
|
+
run_too = True
|
9
|
+
|
10
|
+
|
11
|
+
class TestCombinations(unittest.TestCase):
|
12
|
+
def setUp(self):
|
13
|
+
path_constants = room(254)
|
14
|
+
for path in path_constants:
|
15
|
+
if not os.path.exists(path):
|
16
|
+
self.fail(
|
17
|
+
f"{path} does not exist on your system. If you would like to run tests, please change this path.")
|
18
|
+
|
19
|
+
self.hplc_controller = HPLCController(comm_dir=path_constants[0],
|
20
|
+
method_dir=path_constants[1],
|
21
|
+
data_dir=path_constants[2],
|
22
|
+
sequence_dir=path_constants[3])
|
23
|
+
|
24
|
+
def test_run_method_after_update(self):
|
25
|
+
try:
|
26
|
+
self.hplc_controller.method_controller.switch(DEFAULT_METHOD)
|
27
|
+
rand_method = MethodTimetable(
|
28
|
+
first_row=HPLCMethodParams(
|
29
|
+
organic_modifier=5,
|
30
|
+
flow=0.65,
|
31
|
+
maximum_run_time=2),
|
32
|
+
subsequent_rows=[
|
33
|
+
TimeTableEntry(
|
34
|
+
start_time=0.10,
|
35
|
+
organic_modifer=5,
|
36
|
+
flow=0.34),
|
37
|
+
TimeTableEntry(
|
38
|
+
start_time=1,
|
39
|
+
organic_modifer=98,
|
40
|
+
flow=0.55)])
|
41
|
+
self.hplc_controller.edit_method(rand_method, save=True)
|
42
|
+
if run_too:
|
43
|
+
self.hplc_controller.run_method(experiment_name="changed_method")
|
44
|
+
except Exception as e:
|
45
|
+
self.fail(f"Should have not failed: {e}")
|
46
|
+
|
47
|
+
def test_run_after_table_edit(self):
|
48
|
+
try:
|
49
|
+
self.hplc_controller.switch_sequence(sequence_name=DEFAULT_SEQUENCE)
|
50
|
+
seq_table = self.hplc_controller.load_sequence()
|
51
|
+
seq_table.rows.append(SequenceEntry(
|
52
|
+
vial_location=TenColumn.ONE,
|
53
|
+
method=DEFAULT_METHOD,
|
54
|
+
num_inj=3,
|
55
|
+
inj_vol=4,
|
56
|
+
sample_name="Sampel1",
|
57
|
+
sample_type=SampleType.SAMPLE,
|
58
|
+
))
|
59
|
+
seq_table.rows[0] = SequenceEntry(
|
60
|
+
vial_location=TenColumn.ONE,
|
61
|
+
method=DEFAULT_METHOD,
|
62
|
+
num_inj=3,
|
63
|
+
inj_vol=4,
|
64
|
+
sample_name="Sampel2",
|
65
|
+
sample_type=SampleType.SAMPLE)
|
66
|
+
self.hplc_controller.edit_sequence(seq_table)
|
67
|
+
if run_too:
|
68
|
+
self.hplc_controller.run_sequence()
|
69
|
+
chrom = self.hplc_controller.get_last_run_sequence_data()
|
70
|
+
self.assertTrue(len(chrom) == 2)
|
71
|
+
except Exception as e:
|
72
|
+
self.fail("Failed")
|
73
|
+
|
74
|
+
def test_run_after_existing_row_edit(self):
|
75
|
+
try:
|
76
|
+
self.hplc_controller.switch_sequence(sequence_name=DEFAULT_SEQUENCE)
|
77
|
+
seq_table = self.hplc_controller.load_sequence()
|
78
|
+
self.hplc_controller.edit_sequence_row(seq_entry, 1)
|
79
|
+
if run_too:
|
80
|
+
self.hplc_controller.run_sequence()
|
81
|
+
chrom = self.hplc_controller.get_last_run_sequence_data()
|
82
|
+
self.assertTrue(len(chrom) == 2)
|
83
|
+
except Exception:
|
84
|
+
self.fail("Failed")
|
85
|
+
|
86
|
+
def test_update_method_update_seq_table_run(self):
|
87
|
+
try:
|
88
|
+
self.hplc_controller.method_controller.switch(DEFAULT_METHOD)
|
89
|
+
rand_method = MethodTimetable(
|
90
|
+
first_row=HPLCMethodParams(
|
91
|
+
organic_modifier=5,
|
92
|
+
flow=0.65,
|
93
|
+
maximum_run_time=2),
|
94
|
+
subsequent_rows=[
|
95
|
+
TimeTableEntry(
|
96
|
+
start_time=0.50,
|
97
|
+
organic_modifer=99,
|
98
|
+
flow=0.34)])
|
99
|
+
self.hplc_controller.edit_method(rand_method, save=True)
|
100
|
+
|
101
|
+
self.hplc_controller.switch_sequence(sequence_name=DEFAULT_SEQUENCE)
|
102
|
+
seq_table = SequenceTable(
|
103
|
+
name=DEFAULT_SEQUENCE,
|
104
|
+
rows=[
|
105
|
+
SequenceEntry(
|
106
|
+
vial_location=8320,
|
107
|
+
sample_name="WM-01-001_Cr-Org",
|
108
|
+
method=DEFAULT_METHOD,
|
109
|
+
inj_source=InjectionSource.HIP_ALS,
|
110
|
+
inj_vol=2,
|
111
|
+
num_inj=1,
|
112
|
+
sample_type=SampleType.SAMPLE
|
113
|
+
),
|
114
|
+
SequenceEntry(
|
115
|
+
vial_location=8448,
|
116
|
+
sample_name="WM-01-001_Cr-Aq",
|
117
|
+
method=DEFAULT_METHOD,
|
118
|
+
inj_source=InjectionSource.HIP_ALS,
|
119
|
+
inj_vol=2,
|
120
|
+
num_inj=1,
|
121
|
+
sample_type=SampleType.SAMPLE
|
122
|
+
),
|
123
|
+
]
|
124
|
+
)
|
125
|
+
|
126
|
+
self.hplc_controller.edit_sequence(seq_table)
|
127
|
+
if run_too:
|
128
|
+
self.hplc_controller.preprun()
|
129
|
+
self.hplc_controller.run_sequence()
|
130
|
+
chrom = self.hplc_controller.get_last_run_sequence_data()
|
131
|
+
self.assertTrue(len(chrom) == 2)
|
132
|
+
except Exception:
|
133
|
+
self.fail("Failed")
|
134
|
+
|
135
|
+
def test_run_sequence(self):
|
136
|
+
try:
|
137
|
+
self.hplc_controller.switch_sequence(sequence_name=DEFAULT_SEQUENCE)
|
138
|
+
self.hplc_controller.preprun()
|
139
|
+
self.hplc_controller.run_sequence()
|
140
|
+
chrom = self.hplc_controller.get_last_run_sequence_data()
|
141
|
+
self.assertTrue(len(chrom) == 2)
|
142
|
+
except Exception:
|
143
|
+
self.fail("Failed")
|
@@ -63,6 +63,54 @@ class TestSequence(unittest.TestCase):
|
|
63
63
|
sample_name="Sampel2",
|
64
64
|
sample_type=SampleType.SAMPLE,
|
65
65
|
inj_source=InjectionSource.HIP_ALS
|
66
|
+
),
|
67
|
+
SequenceEntry(
|
68
|
+
vial_location=TenColumn.TEN,
|
69
|
+
method=DEFAULT_METHOD,
|
70
|
+
num_inj=3,
|
71
|
+
inj_vol=4,
|
72
|
+
sample_name="Sampel2",
|
73
|
+
sample_type=SampleType.SAMPLE,
|
74
|
+
inj_source=InjectionSource.HIP_ALS
|
75
|
+
),
|
76
|
+
SequenceEntry(
|
77
|
+
vial_location=TenColumn.THREE,
|
78
|
+
method=DEFAULT_METHOD,
|
79
|
+
num_inj=3,
|
80
|
+
inj_vol=4,
|
81
|
+
sample_name="Sampel2",
|
82
|
+
sample_type=SampleType.SAMPLE,
|
83
|
+
inj_source=InjectionSource.HIP_ALS
|
84
|
+
)
|
85
|
+
]
|
86
|
+
)
|
87
|
+
self.hplc_controller.edit_sequence(seq_table)
|
88
|
+
except Exception:
|
89
|
+
self.fail("Should have not occured")
|
90
|
+
|
91
|
+
def test_edit_entire_table_less_rows(self):
|
92
|
+
self.hplc_controller.switch_sequence(sequence_name=DEFAULT_SEQUENCE)
|
93
|
+
try:
|
94
|
+
seq_table = SequenceTable(
|
95
|
+
name=DEFAULT_SEQUENCE,
|
96
|
+
rows=[
|
97
|
+
SequenceEntry(
|
98
|
+
vial_location=TenColumn.TEN,
|
99
|
+
method=DEFAULT_METHOD,
|
100
|
+
num_inj=3,
|
101
|
+
inj_vol=4,
|
102
|
+
sample_name="Sampel2",
|
103
|
+
sample_type=SampleType.SAMPLE,
|
104
|
+
inj_source=InjectionSource.HIP_ALS
|
105
|
+
),
|
106
|
+
SequenceEntry(
|
107
|
+
vial_location=TenColumn.THREE,
|
108
|
+
method=DEFAULT_METHOD,
|
109
|
+
num_inj=3,
|
110
|
+
inj_vol=4,
|
111
|
+
sample_name="Sampel2",
|
112
|
+
sample_type=SampleType.SAMPLE,
|
113
|
+
inj_source=InjectionSource.HIP_ALS
|
66
114
|
)
|
67
115
|
]
|
68
116
|
)
|
@@ -1,129 +0,0 @@
|
|
1
|
-
import os
|
2
|
-
|
3
|
-
import unittest
|
4
|
-
|
5
|
-
from pychemstation.control import HPLCController
|
6
|
-
from tests.constants import *
|
7
|
-
|
8
|
-
run_too = False
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
class TestCombinations(unittest.TestCase):
|
14
|
-
def setUp(self):
|
15
|
-
path_constants = room(254)
|
16
|
-
for path in path_constants:
|
17
|
-
if not os.path.exists(path):
|
18
|
-
self.fail(
|
19
|
-
f"{path} does not exist on your system. If you would like to run tests, please change this path.")
|
20
|
-
|
21
|
-
self.hplc_controller = HPLCController(comm_dir=path_constants[0],
|
22
|
-
method_dir=path_constants[1],
|
23
|
-
data_dir=path_constants[2],
|
24
|
-
sequence_dir=path_constants[3])
|
25
|
-
|
26
|
-
def test_run_method_after_update(self):
|
27
|
-
self.hplc_controller.method_controller.switch(DEFAULT_METHOD)
|
28
|
-
|
29
|
-
try:
|
30
|
-
rand_method = gen_rand_method()
|
31
|
-
self.hplc_controller.edit_method(rand_method)
|
32
|
-
if run_too:
|
33
|
-
self.hplc_controller.run_method(experiment_name="changed_method")
|
34
|
-
except Exception as e:
|
35
|
-
self.fail(f"Should have not failed: {e}")
|
36
|
-
|
37
|
-
def test_run_after_table_edit(self):
|
38
|
-
try:
|
39
|
-
self.hplc_controller.switch_sequence(sequence_name=DEFAULT_SEQUENCE)
|
40
|
-
seq_table = self.hplc_controller.load_sequence()
|
41
|
-
seq_table.rows[0].vial_location = TenColumn.FIVE
|
42
|
-
seq_table.rows[1].vial_location = TenColumn.ONE
|
43
|
-
seq_table.rows[0].inj_source = InjectionSource.HIP_ALS
|
44
|
-
seq_table.rows[1].inj_source = InjectionSource.MANUAL
|
45
|
-
self.hplc_controller.edit_sequence(seq_table)
|
46
|
-
if run_too:
|
47
|
-
self.hplc_controller.run_sequence(seq_table)
|
48
|
-
chrom = self.hplc_controller.get_last_run_sequence_data()
|
49
|
-
self.assertTrue(len(chrom) == 2)
|
50
|
-
except Exception as e:
|
51
|
-
self.fail("Failed")
|
52
|
-
|
53
|
-
def test_run_after_existing_row_edit(self):
|
54
|
-
try:
|
55
|
-
self.hplc_controller.switch_sequence(sequence_name=DEFAULT_SEQUENCE)
|
56
|
-
seq_table = self.hplc_controller.load_sequence()
|
57
|
-
self.hplc_controller.edit_sequence_row(seq_entry, 1)
|
58
|
-
if run_too:
|
59
|
-
self.hplc_controller.run_sequence(seq_table)
|
60
|
-
chrom = self.hplc_controller.get_last_run_sequence_data()
|
61
|
-
self.assertTrue(len(chrom) == 2)
|
62
|
-
except Exception:
|
63
|
-
self.fail("Failed")
|
64
|
-
|
65
|
-
def test_update_method_update_seq_table_run(self):
|
66
|
-
try:
|
67
|
-
self.hplc_controller.method_controller.switch(DEFAULT_METHOD)
|
68
|
-
rand_method = gen_rand_method()
|
69
|
-
self.hplc_controller.edit_method(rand_method, save=True)
|
70
|
-
|
71
|
-
self.hplc_controller.switch_sequence(sequence_name=DEFAULT_SEQUENCE)
|
72
|
-
seq_table = self.hplc_controller.load_sequence()
|
73
|
-
seq_table.rows[0].vial_location = TenColumn.ONE
|
74
|
-
seq_table.rows[0].inj_source = InjectionSource.HIP_ALS
|
75
|
-
seq_table.rows[1].vial_location = TenColumn.TWO
|
76
|
-
seq_table.rows[1].inj_source = InjectionSource.HIP_ALS
|
77
|
-
self.hplc_controller.edit_sequence(seq_table)
|
78
|
-
|
79
|
-
if run_too:
|
80
|
-
self.hplc_controller.run_sequence(seq_table)
|
81
|
-
chrom = self.hplc_controller.get_last_run_sequence_data()
|
82
|
-
self.assertTrue(len(chrom) == 2)
|
83
|
-
except Exception:
|
84
|
-
self.fail("Failed")
|
85
|
-
|
86
|
-
def test_update_table_then_row(self):
|
87
|
-
try:
|
88
|
-
self.hplc_controller.method_controller.switch(DEFAULT_METHOD)
|
89
|
-
self.hplc_controller.switch_sequence(sequence_name=DEFAULT_SEQUENCE)
|
90
|
-
rand_method = gen_rand_method()
|
91
|
-
self.hplc_controller.edit_method(rand_method, save=True)
|
92
|
-
|
93
|
-
seq_table = self.hplc_controller.load_sequence()
|
94
|
-
seq_table.rows[0].vial_location = TenColumn.ONE
|
95
|
-
seq_table.rows[0].inj_source = InjectionSource.HIP_ALS
|
96
|
-
seq_table.rows[0].method = DEFAULT_METHOD
|
97
|
-
seq_table.rows[1].vial_location = TenColumn.TWO
|
98
|
-
seq_table.rows[1].inj_source = InjectionSource.HIP_ALS
|
99
|
-
seq_table.rows[1].method = DEFAULT_METHOD
|
100
|
-
|
101
|
-
self.hplc_controller.edit_sequence(seq_table)
|
102
|
-
self.hplc_controller.edit_sequence_row(
|
103
|
-
SequenceEntry(
|
104
|
-
vial_location=TenColumn.ONE,
|
105
|
-
method=DEFAULT_METHOD,
|
106
|
-
num_inj=3,
|
107
|
-
inj_vol=4,
|
108
|
-
sample_name="Blank",
|
109
|
-
sample_type=SampleType.BLANK,
|
110
|
-
)
|
111
|
-
)
|
112
|
-
if run_too:
|
113
|
-
self.hplc_controller.run_sequence(seq_table)
|
114
|
-
chrom = self.hplc_controller.get_last_run_sequence_data()
|
115
|
-
self.assertTrue(len(chrom) == 2)
|
116
|
-
except Exception:
|
117
|
-
self.fail("Failed")
|
118
|
-
|
119
|
-
def test_run_after_new_row_edit(self):
|
120
|
-
try:
|
121
|
-
self.hplc_controller.switch_sequence(sequence_name=DEFAULT_SEQUENCE)
|
122
|
-
seq_table = self.hplc_controller.load_sequence()
|
123
|
-
self.hplc_controller.edit_sequence_row(seq_entry, 3)
|
124
|
-
if run_too:
|
125
|
-
self.hplc_controller.run_sequence(seq_table)
|
126
|
-
chrom = self.hplc_controller.get_last_run_sequence_data()
|
127
|
-
self.assertTrue(len(chrom) == 2)
|
128
|
-
except Exception:
|
129
|
-
self.fail("Failed")
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{pychemstation-0.5.3.dev1 → pychemstation-0.5.5}/pychemstation.egg-info/dependency_links.txt
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|