pychemstation 0.10.5__py3-none-any.whl → 0.10.7__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/analysis/__init__.py +8 -1
- pychemstation/control/README.md +1 -1
- pychemstation/control/controllers/__init__.py +2 -2
- pychemstation/control/controllers/abc_tables/__init__.py +0 -0
- pychemstation/control/controllers/abc_tables/abc_comm.py +155 -0
- pychemstation/control/controllers/abc_tables/device.py +20 -0
- pychemstation/control/controllers/{tables/table.py → abc_tables/run.py} +58 -201
- pychemstation/control/controllers/abc_tables/table.py +230 -0
- pychemstation/control/controllers/comm.py +26 -101
- pychemstation/control/controllers/{tables → data_aq}/method.py +12 -15
- pychemstation/control/controllers/{tables → data_aq}/sequence.py +168 -119
- pychemstation/control/controllers/devices/__init__.py +3 -0
- pychemstation/control/controllers/devices/injector.py +61 -28
- pychemstation/control/hplc.py +42 -26
- pychemstation/utils/injector_types.py +22 -2
- pychemstation/utils/macro.py +11 -0
- pychemstation/utils/mocking/__init__.py +0 -0
- pychemstation/utils/mocking/mock_comm.py +5 -0
- pychemstation/utils/mocking/mock_hplc.py +2 -0
- pychemstation/utils/sequence_types.py +22 -2
- pychemstation/utils/table_types.py +6 -0
- pychemstation/utils/tray_types.py +36 -1
- {pychemstation-0.10.5.dist-info → pychemstation-0.10.7.dist-info}/METADATA +3 -3
- pychemstation-0.10.7.dist-info/RECORD +42 -0
- pychemstation/control/controllers/devices/device.py +0 -74
- pychemstation-0.10.5.dist-info/RECORD +0 -36
- /pychemstation/control/controllers/{tables → data_aq}/__init__.py +0 -0
- {pychemstation-0.10.5.dist-info → pychemstation-0.10.7.dist-info}/WHEEL +0 -0
- {pychemstation-0.10.5.dist-info → pychemstation-0.10.7.dist-info}/licenses/LICENSE +0 -0
@@ -1,4 +1,11 @@
|
|
1
1
|
from .process_report import CSVProcessor
|
2
2
|
from .process_report import TXTProcessor
|
3
|
+
from .chromatogram import AgilentChannelChromatogramData
|
4
|
+
from .chromatogram import AgilentHPLCChromatogram
|
3
5
|
|
4
|
-
__all__ = [
|
6
|
+
__all__ = [
|
7
|
+
"CSVProcessor",
|
8
|
+
"TXTProcessor",
|
9
|
+
"AgilentChannelChromatogramData",
|
10
|
+
"AgilentHPLCChromatogram",
|
11
|
+
]
|
pychemstation/control/README.md
CHANGED
@@ -10,7 +10,7 @@ DATA_DIR_2 = "C:\\Users\\Public\\Documents\\ChemStation\\2\\Data"
|
|
10
10
|
DATA_DIR_3 = "C:\\Users\\Public\\Documents\\ChemStation\\3\\Data"
|
11
11
|
|
12
12
|
# Initialize HPLC Controller
|
13
|
-
hplc_controller = HPLCController(
|
13
|
+
hplc_controller = HPLCController(extra_data_dirs=[DATA_DIR_2, DATA_DIR_3],
|
14
14
|
comm_dir=DEFAULT_COMMAND_PATH,
|
15
15
|
method_dir=DEFAULT_METHOD_DIR,
|
16
16
|
sequence_dir=SEQUENCE_DIR)
|
File without changes
|
@@ -0,0 +1,155 @@
|
|
1
|
+
"""
|
2
|
+
Module to provide API for the communication with Agilent HPLC systems.
|
3
|
+
|
4
|
+
HPLCController sends commands to Chemstation software via a command file.
|
5
|
+
Answers are received via reply file. On the Chemstation side, a custom
|
6
|
+
Macro monitors the command file, executes commands and writes to the reply file.
|
7
|
+
Each command is given a number (cmd_no) to keep track of which commands have
|
8
|
+
been processed.
|
9
|
+
|
10
|
+
Authors: Alexander Hammer, Hessam Mehr, Lucy Hao
|
11
|
+
"""
|
12
|
+
|
13
|
+
import abc
|
14
|
+
import os
|
15
|
+
import time
|
16
|
+
from abc import abstractmethod
|
17
|
+
from typing import Union
|
18
|
+
|
19
|
+
from result import Err, Ok, Result
|
20
|
+
|
21
|
+
from ....utils.macro import Status, HPLCAvailStatus, Command, Response
|
22
|
+
|
23
|
+
|
24
|
+
class ABCCommunicationController(abc.ABC):
|
25
|
+
"""
|
26
|
+
Abstract class representing the communication controller.
|
27
|
+
"""
|
28
|
+
|
29
|
+
# maximum command number
|
30
|
+
MAX_CMD_NO = 255
|
31
|
+
|
32
|
+
def __init__(
|
33
|
+
self,
|
34
|
+
comm_dir: str,
|
35
|
+
cmd_file: str = "cmd",
|
36
|
+
reply_file: str = "reply",
|
37
|
+
offline: bool = False,
|
38
|
+
debug: bool = False,
|
39
|
+
):
|
40
|
+
"""
|
41
|
+
:param comm_dir:
|
42
|
+
:param cmd_file: Name of command file
|
43
|
+
:param reply_file: Name of reply file
|
44
|
+
:param debug: whether to save log of sent commands
|
45
|
+
"""
|
46
|
+
if not offline:
|
47
|
+
self.debug = debug
|
48
|
+
if os.path.isdir(comm_dir):
|
49
|
+
self.cmd_file = os.path.join(comm_dir, cmd_file)
|
50
|
+
self.reply_file = os.path.join(comm_dir, reply_file)
|
51
|
+
self.cmd_no = 0
|
52
|
+
else:
|
53
|
+
raise FileNotFoundError(f"comm_dir: {comm_dir} not found.")
|
54
|
+
|
55
|
+
# Create files for Chemstation to communicate with Python
|
56
|
+
open(self.cmd_file, "a").close()
|
57
|
+
open(self.reply_file, "a").close()
|
58
|
+
|
59
|
+
self.reset_cmd_counter()
|
60
|
+
self._most_recent_hplc_status: Status = self.get_status()
|
61
|
+
self.send("Local Rows")
|
62
|
+
|
63
|
+
@abstractmethod
|
64
|
+
def get_num_val(self, cmd: str) -> Union[int, float]:
|
65
|
+
pass
|
66
|
+
|
67
|
+
@abstractmethod
|
68
|
+
def get_text_val(self, cmd: str) -> str:
|
69
|
+
pass
|
70
|
+
|
71
|
+
@abstractmethod
|
72
|
+
def get_status(self) -> Status:
|
73
|
+
pass
|
74
|
+
|
75
|
+
@abstractmethod
|
76
|
+
def _send(self, cmd: str, cmd_no: int, num_attempts=5) -> None:
|
77
|
+
pass
|
78
|
+
|
79
|
+
@abstractmethod
|
80
|
+
def _receive(self, cmd_no: int, num_attempts=100) -> Result[str, str]:
|
81
|
+
pass
|
82
|
+
|
83
|
+
def set_status(self):
|
84
|
+
"""Updates current status of HPLC machine"""
|
85
|
+
self._most_recent_hplc_status = self.get_status()
|
86
|
+
|
87
|
+
def check_if_not_running(self) -> bool:
|
88
|
+
"""Checks if HPLC machine is in an available state, meaning a state that data is not being written.
|
89
|
+
|
90
|
+
:return: whether the HPLC machine is in a safe state to retrieve data back."""
|
91
|
+
self.set_status()
|
92
|
+
hplc_avail = isinstance(self._most_recent_hplc_status, HPLCAvailStatus)
|
93
|
+
time.sleep(5)
|
94
|
+
self.set_status()
|
95
|
+
hplc_actually_avail = isinstance(self._most_recent_hplc_status, HPLCAvailStatus)
|
96
|
+
return hplc_avail and hplc_actually_avail
|
97
|
+
|
98
|
+
def sleepy_send(self, cmd: Union[Command, str]):
|
99
|
+
self.send("Sleep 0.1")
|
100
|
+
self.send(cmd)
|
101
|
+
self.send("Sleep 0.1")
|
102
|
+
|
103
|
+
def send(self, cmd: Union[Command, str]):
|
104
|
+
"""Sends a command to Chemstation.
|
105
|
+
|
106
|
+
:param cmd: Command to be sent to HPLC
|
107
|
+
"""
|
108
|
+
if self.cmd_no == self.MAX_CMD_NO:
|
109
|
+
self.reset_cmd_counter()
|
110
|
+
|
111
|
+
cmd_to_send: str = cmd.value if isinstance(cmd, Command) else cmd
|
112
|
+
self.cmd_no += 1
|
113
|
+
self._send(cmd_to_send, self.cmd_no)
|
114
|
+
if self.debug:
|
115
|
+
f = open("out.txt", "a")
|
116
|
+
f.write(cmd_to_send + "\n")
|
117
|
+
f.close()
|
118
|
+
|
119
|
+
def receive(self) -> Result[Response, str]:
|
120
|
+
"""Returns messages received in reply file.
|
121
|
+
|
122
|
+
:return: ChemStation response
|
123
|
+
"""
|
124
|
+
num_response_prefix = "Numerical Responses:"
|
125
|
+
str_response_prefix = "String Responses:"
|
126
|
+
possible_response = self._receive(self.cmd_no)
|
127
|
+
if possible_response.is_ok():
|
128
|
+
lines = possible_response.ok_value.splitlines()
|
129
|
+
for line in lines:
|
130
|
+
if str_response_prefix in line and num_response_prefix in line:
|
131
|
+
string_responses_dirty, _, numerical_responses = line.partition(
|
132
|
+
num_response_prefix
|
133
|
+
)
|
134
|
+
_, _, string_responses = string_responses_dirty.partition(
|
135
|
+
str_response_prefix
|
136
|
+
)
|
137
|
+
return Ok(
|
138
|
+
Response(
|
139
|
+
string_response=string_responses.strip(),
|
140
|
+
num_response=float(numerical_responses.strip()),
|
141
|
+
)
|
142
|
+
)
|
143
|
+
return Err("Could not retrieve HPLC response")
|
144
|
+
else:
|
145
|
+
return Err(f"Could not establish response to HPLC: {possible_response}")
|
146
|
+
|
147
|
+
def reset_cmd_counter(self):
|
148
|
+
"""Resets the command counter."""
|
149
|
+
self._send(Command.RESET_COUNTER_CMD.value, cmd_no=self.MAX_CMD_NO + 1)
|
150
|
+
self._receive(cmd_no=self.MAX_CMD_NO + 1)
|
151
|
+
self.cmd_no = 0
|
152
|
+
|
153
|
+
def stop_macro(self):
|
154
|
+
"""Stops Macro execution. Connection will be lost."""
|
155
|
+
self.send(Command.STOP_MACRO_CMD)
|
@@ -0,0 +1,20 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from abc import ABC
|
4
|
+
|
5
|
+
from ....control.controllers import CommunicationController
|
6
|
+
from ....utils.table_types import Table
|
7
|
+
from .table import ABCTableController
|
8
|
+
|
9
|
+
|
10
|
+
class DeviceController(ABCTableController, ABC):
|
11
|
+
def __init__(
|
12
|
+
self, controller: CommunicationController, table: Table, offline: bool
|
13
|
+
):
|
14
|
+
super().__init__(controller=controller, table=table)
|
15
|
+
self.offline = offline
|
16
|
+
|
17
|
+
def __new__(cls, *args, **kwargs):
|
18
|
+
if cls is ABCTableController:
|
19
|
+
raise TypeError(f"only children of '{cls.__name__}' may be instantiated")
|
20
|
+
return object.__new__(cls)
|
@@ -11,11 +11,16 @@ import math
|
|
11
11
|
import os
|
12
12
|
import time
|
13
13
|
import warnings
|
14
|
-
from typing import Dict, List, Optional, Tuple, Union
|
14
|
+
from typing import Dict, List, Optional, Tuple, Union, Set
|
15
15
|
|
16
16
|
import polling
|
17
17
|
import rainbow as rb
|
18
|
-
from result import Err,
|
18
|
+
from result import Err, Ok, Result
|
19
|
+
|
20
|
+
from pychemstation.analysis.chromatogram import (
|
21
|
+
AgilentChannelChromatogramData,
|
22
|
+
AgilentHPLCChromatogram,
|
23
|
+
)
|
19
24
|
|
20
25
|
from ....analysis.process_report import (
|
21
26
|
AgilentReport,
|
@@ -24,19 +29,16 @@ from ....analysis.process_report import (
|
|
24
29
|
TXTProcessor,
|
25
30
|
)
|
26
31
|
from ....control.controllers.comm import CommunicationController
|
27
|
-
from
|
28
|
-
AgilentChannelChromatogramData,
|
29
|
-
AgilentHPLCChromatogram,
|
30
|
-
)
|
31
|
-
from ....utils.macro import Command, HPLCRunningStatus, Response
|
32
|
+
from ....utils.macro import Command, HPLCRunningStatus
|
32
33
|
from ....utils.method_types import MethodDetails
|
33
34
|
from ....utils.sequence_types import SequenceTable
|
34
|
-
from ....utils.table_types import
|
35
|
+
from ....utils.table_types import T, Table
|
36
|
+
from .table import ABCTableController
|
35
37
|
|
36
38
|
TableType = Union[MethodDetails, SequenceTable]
|
37
39
|
|
38
40
|
|
39
|
-
class
|
41
|
+
class RunController(ABCTableController, abc.ABC):
|
40
42
|
def __init__(
|
41
43
|
self,
|
42
44
|
controller: Optional[CommunicationController],
|
@@ -45,11 +47,11 @@ class TableController(abc.ABC):
|
|
45
47
|
table: Table,
|
46
48
|
offline: bool = False,
|
47
49
|
):
|
48
|
-
|
49
|
-
self.table_locator = table
|
50
|
+
super().__init__(controller=controller, table=table)
|
50
51
|
self.table_state: Optional[TableType] = None
|
51
52
|
self.curr_run_starting_time: Optional[float] = None
|
52
53
|
self.timeout: Optional[float] = None
|
54
|
+
self.current_run_child_files: Set[str] = set()
|
53
55
|
|
54
56
|
if not offline:
|
55
57
|
if src and not os.path.isdir(src):
|
@@ -76,179 +78,34 @@ class TableController(abc.ABC):
|
|
76
78
|
self.uv: Dict[int, AgilentHPLCChromatogram] = {}
|
77
79
|
self.data_files: List = []
|
78
80
|
|
79
|
-
def
|
80
|
-
if
|
81
|
-
|
82
|
-
|
83
|
-
return self.controller.receive()
|
84
|
-
except IndexError:
|
85
|
-
continue
|
86
|
-
return Err("Could not parse response")
|
87
|
-
else:
|
88
|
-
raise ValueError("Controller is offline!")
|
89
|
-
|
90
|
-
def send(self, cmd: Union[Command, str]):
|
91
|
-
if not self.controller:
|
92
|
-
raise RuntimeError(
|
93
|
-
"Communication controller must be initialized before sending command. It is currently in offline mode."
|
94
|
-
)
|
95
|
-
self.controller.send(cmd)
|
96
|
-
|
97
|
-
def sleepy_send(self, cmd: Union[Command, str]):
|
98
|
-
if self.controller:
|
99
|
-
self.controller.sleepy_send(cmd)
|
100
|
-
else:
|
101
|
-
raise ValueError("Controller is offline")
|
102
|
-
|
103
|
-
def sleep(self, seconds: int):
|
104
|
-
"""
|
105
|
-
Tells the HPLC to wait for a specified number of seconds.
|
106
|
-
|
107
|
-
:param seconds: number of seconds to wait
|
108
|
-
"""
|
109
|
-
self.send(Command.SLEEP_CMD.value.format(seconds=seconds))
|
110
|
-
|
111
|
-
def get_num(self, row: int, col_name: RegisterFlag) -> Union[int, float]:
|
112
|
-
if self.controller:
|
113
|
-
return self.controller.get_num_val(
|
114
|
-
TableOperation.GET_ROW_VAL.value.format(
|
115
|
-
register=self.table_locator.register,
|
116
|
-
table_name=self.table_locator.name,
|
117
|
-
row=row,
|
118
|
-
col_name=col_name.value,
|
119
|
-
)
|
120
|
-
)
|
121
|
-
else:
|
122
|
-
raise ValueError("Controller is offline")
|
123
|
-
|
124
|
-
def get_text(self, row: int, col_name: RegisterFlag) -> str:
|
125
|
-
if self.controller:
|
126
|
-
return self.controller.get_text_val(
|
127
|
-
TableOperation.GET_ROW_TEXT.value.format(
|
128
|
-
register=self.table_locator.register,
|
129
|
-
table_name=self.table_locator.name,
|
130
|
-
row=row,
|
131
|
-
col_name=col_name.value,
|
132
|
-
)
|
133
|
-
)
|
134
|
-
else:
|
135
|
-
raise ValueError("Controller is offline")
|
136
|
-
|
137
|
-
def add_new_col_num(self, col_name: RegisterFlag, val: Union[int, float]):
|
138
|
-
self.sleepy_send(
|
139
|
-
TableOperation.NEW_COL_VAL.value.format(
|
140
|
-
register=self.table_locator.register,
|
141
|
-
table_name=self.table_locator.name,
|
142
|
-
col_name=col_name,
|
143
|
-
val=val,
|
144
|
-
)
|
145
|
-
)
|
146
|
-
|
147
|
-
def add_new_col_text(self, col_name: RegisterFlag, val: str):
|
148
|
-
self.sleepy_send(
|
149
|
-
TableOperation.NEW_COL_TEXT.value.format(
|
150
|
-
register=self.table_locator.register,
|
151
|
-
table_name=self.table_locator.name,
|
152
|
-
col_name=col_name,
|
153
|
-
val=val,
|
154
|
-
)
|
155
|
-
)
|
156
|
-
|
157
|
-
def _edit_row_num(
|
158
|
-
self, col_name: RegisterFlag, val: Union[int, float], row: Optional[int] = None
|
159
|
-
):
|
160
|
-
self.sleepy_send(
|
161
|
-
TableOperation.EDIT_ROW_VAL.value.format(
|
162
|
-
register=self.table_locator.register,
|
163
|
-
table_name=self.table_locator.name,
|
164
|
-
row=row if row is not None else "Rows",
|
165
|
-
col_name=col_name,
|
166
|
-
val=val,
|
167
|
-
)
|
168
|
-
)
|
169
|
-
|
170
|
-
def _edit_row_text(
|
171
|
-
self, col_name: RegisterFlag, val: str, row: Optional[int] = None
|
172
|
-
):
|
173
|
-
self.sleepy_send(
|
174
|
-
TableOperation.EDIT_ROW_TEXT.value.format(
|
175
|
-
register=self.table_locator.register,
|
176
|
-
table_name=self.table_locator.name,
|
177
|
-
row=row if row is not None else "Rows",
|
178
|
-
col_name=col_name,
|
179
|
-
val=val,
|
180
|
-
)
|
181
|
-
)
|
81
|
+
def __new__(cls, *args, **kwargs):
|
82
|
+
if cls is RunController:
|
83
|
+
raise TypeError(f"only children of '{cls.__name__}' may be instantiated")
|
84
|
+
return object.__new__(cls)
|
182
85
|
|
183
86
|
@abc.abstractmethod
|
184
|
-
def
|
87
|
+
def fuzzy_match_most_recent_folder(
|
88
|
+
self, most_recent_folder: T, child_files: Set[str]
|
89
|
+
) -> Result[T, str]:
|
185
90
|
pass
|
186
91
|
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
row=row,
|
193
|
-
)
|
194
|
-
)
|
195
|
-
|
196
|
-
def add_row(self):
|
197
|
-
"""
|
198
|
-
Adds a row to the provided table for currently loaded method or sequence.
|
199
|
-
"""
|
200
|
-
self.sleepy_send(
|
201
|
-
TableOperation.NEW_ROW.value.format(
|
202
|
-
register=self.table_locator.register, table_name=self.table_locator.name
|
203
|
-
)
|
204
|
-
)
|
205
|
-
|
206
|
-
def delete_table(self):
|
207
|
-
"""
|
208
|
-
Deletes the table for the current loaded method or sequence.
|
209
|
-
"""
|
210
|
-
self.sleepy_send(
|
211
|
-
TableOperation.DELETE_TABLE.value.format(
|
212
|
-
register=self.table_locator.register, table_name=self.table_locator.name
|
213
|
-
)
|
214
|
-
)
|
215
|
-
|
216
|
-
def new_table(self):
|
217
|
-
"""
|
218
|
-
Creates the table for the currently loaded method or sequence.
|
219
|
-
"""
|
220
|
-
self.send(
|
221
|
-
TableOperation.CREATE_TABLE.value.format(
|
222
|
-
register=self.table_locator.register, table_name=self.table_locator.name
|
223
|
-
)
|
224
|
-
)
|
92
|
+
@abc.abstractmethod
|
93
|
+
def get_data(
|
94
|
+
self, custom_path: Optional[str] = None
|
95
|
+
) -> Union[List[AgilentChannelChromatogramData], AgilentChannelChromatogramData]:
|
96
|
+
pass
|
225
97
|
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
col_name=RegisterFlag.NUM_ROWS,
|
232
|
-
)
|
233
|
-
)
|
234
|
-
self.send(
|
235
|
-
Command.GET_ROWS_CMD.value.format(
|
236
|
-
register=self.table_locator.register,
|
237
|
-
table_name=self.table_locator.name,
|
238
|
-
col_name=RegisterFlag.NUM_ROWS,
|
239
|
-
)
|
240
|
-
)
|
241
|
-
if self.controller:
|
242
|
-
res = self.controller.receive()
|
243
|
-
else:
|
244
|
-
raise ValueError("Controller is offline")
|
98
|
+
@abc.abstractmethod
|
99
|
+
def get_data_uv(
|
100
|
+
self, custom_path: str | None = None
|
101
|
+
) -> Dict[int, AgilentHPLCChromatogram]:
|
102
|
+
pass
|
245
103
|
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
return Err("No rows could be read.")
|
104
|
+
@abc.abstractmethod
|
105
|
+
def get_report(
|
106
|
+
self, custom_path: str, report_type: ReportType = ReportType.TXT
|
107
|
+
) -> List[AgilentReport]:
|
108
|
+
pass
|
252
109
|
|
253
110
|
def check_hplc_is_running(self) -> bool:
|
254
111
|
if self.controller:
|
@@ -269,6 +126,12 @@ class TableController(abc.ABC):
|
|
269
126
|
|
270
127
|
def check_hplc_run_finished(self) -> Tuple[float, bool]:
|
271
128
|
if self.controller:
|
129
|
+
try:
|
130
|
+
_, current_run_file = self.get_current_run_data_dir_file()
|
131
|
+
sample_file, extension, _ = current_run_file.partition(".D")
|
132
|
+
self.current_run_child_files.add(sample_file)
|
133
|
+
except Exception:
|
134
|
+
pass
|
272
135
|
done_running = self.controller.check_if_not_running()
|
273
136
|
if self.curr_run_starting_time and self.timeout:
|
274
137
|
time_passed = time.time() - self.curr_run_starting_time
|
@@ -290,6 +153,7 @@ class TableController(abc.ABC):
|
|
290
153
|
|
291
154
|
:return: Data file object containing most recent run file information.
|
292
155
|
"""
|
156
|
+
self.current_run_child_files = set()
|
293
157
|
if self.timeout is not None:
|
294
158
|
finished_run = False
|
295
159
|
minutes = math.ceil(self.timeout / 60)
|
@@ -319,7 +183,9 @@ class TableController(abc.ABC):
|
|
319
183
|
else:
|
320
184
|
raise ValueError("Timeout value is None, no comparison can be made.")
|
321
185
|
|
322
|
-
check_folder = self.fuzzy_match_most_recent_folder(
|
186
|
+
check_folder = self.fuzzy_match_most_recent_folder(
|
187
|
+
self.data_files[-1], self.current_run_child_files
|
188
|
+
)
|
323
189
|
if check_folder.is_ok() and finished_run:
|
324
190
|
return check_folder
|
325
191
|
elif check_folder.is_ok():
|
@@ -334,28 +200,6 @@ class TableController(abc.ABC):
|
|
334
200
|
return self.data_files[-1]
|
335
201
|
return Err("Run did not complete as expected")
|
336
202
|
|
337
|
-
@abc.abstractmethod
|
338
|
-
def fuzzy_match_most_recent_folder(self, most_recent_folder: T) -> Result[T, str]:
|
339
|
-
pass
|
340
|
-
|
341
|
-
@abc.abstractmethod
|
342
|
-
def get_data(
|
343
|
-
self, custom_path: Optional[str] = None
|
344
|
-
) -> Union[List[AgilentChannelChromatogramData], AgilentChannelChromatogramData]:
|
345
|
-
pass
|
346
|
-
|
347
|
-
@abc.abstractmethod
|
348
|
-
def get_data_uv(
|
349
|
-
self, custom_path: str | None = None
|
350
|
-
) -> Dict[int, AgilentHPLCChromatogram]:
|
351
|
-
pass
|
352
|
-
|
353
|
-
@abc.abstractmethod
|
354
|
-
def get_report(
|
355
|
-
self, custom_path: str, report_type: ReportType = ReportType.TXT
|
356
|
-
) -> List[AgilentReport]:
|
357
|
-
pass
|
358
|
-
|
359
203
|
def get_uv_spectrum(self, path: str):
|
360
204
|
data_uv = rb.agilent.chemstation.parse_file(os.path.join(path, "DAD1.UV"))
|
361
205
|
times = data_uv.xlabels
|
@@ -397,3 +241,16 @@ class TableController(abc.ABC):
|
|
397
241
|
def _reset_time(self):
|
398
242
|
self.curr_run_starting_time = None
|
399
243
|
self.timeout = None
|
244
|
+
|
245
|
+
def get_current_run_data_dir_file(self) -> Tuple[str, str]:
|
246
|
+
self.send(Command.GET_CURRENT_RUN_DATA_DIR)
|
247
|
+
full_path_name = self.receive()
|
248
|
+
self.send(Command.GET_CURRENT_RUN_DATA_FILE)
|
249
|
+
current_sample_file = self.receive()
|
250
|
+
if full_path_name.is_ok() and current_sample_file.is_ok():
|
251
|
+
return (
|
252
|
+
full_path_name.ok_value.string_response,
|
253
|
+
current_sample_file.ok_value.string_response,
|
254
|
+
)
|
255
|
+
else:
|
256
|
+
raise ValueError("Couldn't read data dir and file.")
|