pychemstation 0.5.14.dev1__py3-none-any.whl → 0.6.0__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/process_report.py +219 -0
- pychemstation/control/controllers/devices/dad.py +0 -0
- pychemstation/control/controllers/devices/injector.py +109 -3
- pychemstation/control/controllers/tables/method.py +13 -4
- pychemstation/control/controllers/tables/table.py +20 -20
- pychemstation/control/hplc.py +15 -3
- pychemstation/utils/injector_types.py +29 -7
- pychemstation/utils/macro.py +1 -1
- pychemstation/utils/method_types.py +3 -1
- pychemstation/utils/table_types.py +20 -0
- {pychemstation-0.5.14.dev1.dist-info → pychemstation-0.6.0.dist-info}/METADATA +1 -1
- {pychemstation-0.5.14.dev1.dist-info → pychemstation-0.6.0.dist-info}/RECORD +22 -19
- tests/constants.py +1 -1
- tests/test_comb.py +1 -1
- tests/test_comm.py +1 -1
- tests/test_inj.py +5 -10
- tests/test_method.py +19 -1
- tests/test_proc_rep.py +27 -0
- tests/test_sequence.py +1 -2
- {pychemstation-0.5.14.dev1.dist-info → pychemstation-0.6.0.dist-info}/LICENSE +0 -0
- {pychemstation-0.5.14.dev1.dist-info → pychemstation-0.6.0.dist-info}/WHEEL +0 -0
- {pychemstation-0.5.14.dev1.dist-info → pychemstation-0.6.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,219 @@
|
|
1
|
+
"""
|
2
|
+
pip install pandas
|
3
|
+
pip install aghplctools==4.8.6
|
4
|
+
"""
|
5
|
+
|
6
|
+
import os
|
7
|
+
import re
|
8
|
+
from dataclasses import dataclass
|
9
|
+
from typing import List, AnyStr
|
10
|
+
|
11
|
+
import pandas as pd
|
12
|
+
from aghplctools.ingestion.text import _no_peaks_re, _area_report_re, _header_block_re, _signal_info_re, \
|
13
|
+
_signal_table_re, chunk_string
|
14
|
+
from result import Result, Err, Ok
|
15
|
+
|
16
|
+
|
17
|
+
@dataclass
|
18
|
+
class AgilentPeak:
|
19
|
+
peak_number: int
|
20
|
+
retention_time: float
|
21
|
+
peak_type: str
|
22
|
+
width: float
|
23
|
+
area: float
|
24
|
+
height: float
|
25
|
+
height_percent: float
|
26
|
+
|
27
|
+
|
28
|
+
_column_re_dictionary = { # regex matches for column and unit combinations
|
29
|
+
'Peak': { # peak index
|
30
|
+
'#': '[ ]+(?P<Peak>[\d]+)', # number
|
31
|
+
},
|
32
|
+
'RetTime': { # retention time
|
33
|
+
'[min]': '(?P<RetTime>[\d]+.[\d]+)', # minutes
|
34
|
+
},
|
35
|
+
'Type': { # peak type
|
36
|
+
'': '(?P<Type>[A-Z]{1,3}(?: [A-Z]{1,2})*)', # todo this is different from <4.8.8 aghplc tools
|
37
|
+
},
|
38
|
+
'Width': { # peak width
|
39
|
+
'[min]': '(?P<Width>[\d]+.[\d]+[e+-]*[\d]+)',
|
40
|
+
},
|
41
|
+
'Area': { # peak area
|
42
|
+
'[mAU*s]': '(?P<Area>[\d]+.[\d]+[e+-]*[\d]+)', # area units
|
43
|
+
'%': '(?P<percent>[\d]+.[\d]+[e+-]*[\d]+)', # percent
|
44
|
+
},
|
45
|
+
'Height': { # peak height
|
46
|
+
'[mAU]': '(?P<Height>[\d]+.[\d]+[e+-]*[\d]+)',
|
47
|
+
},
|
48
|
+
'Name': {
|
49
|
+
'': '(?P<Name>[^\s]+(?:\s[^\s]+)*)', # peak name
|
50
|
+
},
|
51
|
+
}
|
52
|
+
|
53
|
+
|
54
|
+
def build_peak_regex(signal_table: str):
|
55
|
+
"""
|
56
|
+
Builds a peak regex from a signal table
|
57
|
+
|
58
|
+
:param signal_table: block of lines associated with an area table
|
59
|
+
:return: peak line regex object (<=3.6 _sre.SRE_PATTERN, >=3.7 re.Pattern)
|
60
|
+
"""
|
61
|
+
split_table = signal_table.split('\n')
|
62
|
+
if len(split_table) <= 4: # catch peak table with no values
|
63
|
+
return None
|
64
|
+
# todo verify that these indicies are always true
|
65
|
+
column_line = split_table[2] # table column line
|
66
|
+
unit_line = split_table[3] # column unit line
|
67
|
+
length_line = [len(val) + 1 for val in split_table[4].split('|')] # length line
|
68
|
+
|
69
|
+
# iterate over header values and units to build peak table regex
|
70
|
+
peak_re_string = []
|
71
|
+
for header, unit in zip(
|
72
|
+
chunk_string(column_line, length_line),
|
73
|
+
chunk_string(unit_line, length_line)
|
74
|
+
):
|
75
|
+
if header == '': # todo create a better catch for an undefined header
|
76
|
+
continue
|
77
|
+
try:
|
78
|
+
peak_re_string.append(
|
79
|
+
_column_re_dictionary[header][unit] # append the appropriate regex
|
80
|
+
)
|
81
|
+
except KeyError: # catch for undefined regexes (need to be built)
|
82
|
+
raise KeyError(f'The header/unit combination "{header}" "{unit}" is not defined in the peak regex '
|
83
|
+
f'dictionary. Let Lars know.')
|
84
|
+
return re.compile(
|
85
|
+
'[ ]+'.join(peak_re_string) # constructed string delimited by 1 or more spaces
|
86
|
+
+ '[\s]*' # and any remaining white space
|
87
|
+
)
|
88
|
+
|
89
|
+
|
90
|
+
# todo should be able to use the parse_area_report method of aghplctools v4.8.8
|
91
|
+
|
92
|
+
def parse_area_report(report_text: str) -> dict:
|
93
|
+
"""
|
94
|
+
Interprets report text and parses the area report section, converting it to dictionary.
|
95
|
+
|
96
|
+
:param report_text: plain text version of the report.
|
97
|
+
:raises ValueError: if there are no peaks defined in the report text file
|
98
|
+
:return: dictionary of signals in the form
|
99
|
+
dict[wavelength][retention time (float)][Width/Area/Height/etc.]
|
100
|
+
"""
|
101
|
+
if re.search(_no_peaks_re, report_text): # There are no peaks in Report.txt
|
102
|
+
raise ValueError(f'No peaks found in Report.txt')
|
103
|
+
blocks = _header_block_re.split(report_text)
|
104
|
+
signals = {} # output dictionary
|
105
|
+
for ind, block in enumerate(blocks):
|
106
|
+
# area report block
|
107
|
+
if _area_report_re.match(block): # match area report block
|
108
|
+
# break into signal blocks
|
109
|
+
signal_blocks = _signal_table_re.split(blocks[ind + 1])
|
110
|
+
# iterate over signal blocks
|
111
|
+
for table in signal_blocks:
|
112
|
+
si = _signal_info_re.match(table)
|
113
|
+
if si is not None:
|
114
|
+
# some error state (e.g. 'not found')
|
115
|
+
if si.group('error') != '':
|
116
|
+
continue
|
117
|
+
wavelength = float(si.group('wavelength'))
|
118
|
+
if wavelength in signals:
|
119
|
+
# placeholder error raise just in case (this probably won't happen)
|
120
|
+
raise KeyError(
|
121
|
+
f'The wavelength {float(si.group("wavelength"))} is already in the signals dictionary')
|
122
|
+
signals[wavelength] = {}
|
123
|
+
# build peak regex
|
124
|
+
peak_re = build_peak_regex(table)
|
125
|
+
if peak_re is None: # if there are no columns (empty table), continue
|
126
|
+
continue
|
127
|
+
for line in table.split('\n'):
|
128
|
+
peak = peak_re.match(line)
|
129
|
+
if peak is not None:
|
130
|
+
signals[wavelength][float(peak.group('RetTime'))] = {}
|
131
|
+
current = signals[wavelength][float(peak.group('RetTime'))]
|
132
|
+
for key in _column_re_dictionary:
|
133
|
+
if key in peak.re.groupindex:
|
134
|
+
try: # try float conversion, otherwise continue
|
135
|
+
value = float(peak.group(key))
|
136
|
+
except ValueError:
|
137
|
+
value = peak.group(key)
|
138
|
+
current[key] = value
|
139
|
+
else: # ensures defined
|
140
|
+
current[key] = None
|
141
|
+
return signals
|
142
|
+
|
143
|
+
|
144
|
+
def process_export_report(file_path, target_wavelengths=None, min_retention_time=0, max_retention_time=999):
|
145
|
+
# # Pull signals from the file
|
146
|
+
# from aghplctools.ingestion.text import pull_hplc_area_from_txt
|
147
|
+
# signals = pull_hplc_area_from_txt(file_path)
|
148
|
+
|
149
|
+
with open(file_path, 'r', encoding='utf-16') as openfile:
|
150
|
+
text = openfile.read()
|
151
|
+
|
152
|
+
try:
|
153
|
+
signals = parse_area_report(text)
|
154
|
+
except ValueError as e:
|
155
|
+
# value error thrown if there are no peaks found in the report
|
156
|
+
print(e)
|
157
|
+
return [], [], []
|
158
|
+
|
159
|
+
# filter wavelengths by the ones to keep
|
160
|
+
if target_wavelengths is not None:
|
161
|
+
signals = {key: signals[key] for key in target_wavelengths if key in signals}
|
162
|
+
|
163
|
+
wavelengths = []
|
164
|
+
retention_times = []
|
165
|
+
areas = []
|
166
|
+
|
167
|
+
for wavelength, wavelength_dict in signals.items():
|
168
|
+
for ret_time, ret_time_dict in wavelength_dict.items():
|
169
|
+
if min_retention_time <= ret_time <= max_retention_time:
|
170
|
+
wavelengths.append(wavelength)
|
171
|
+
retention_times.append(ret_time)
|
172
|
+
areas.append(ret_time_dict['Area'])
|
173
|
+
|
174
|
+
return wavelengths, retention_times, areas
|
175
|
+
|
176
|
+
|
177
|
+
def process_folder(folder_path, target_wavelengths=None, min_retention_time=0, max_retention_time=999):
|
178
|
+
# folder path is the path to the overall folder, and inside there should be subfolders for each LC sample
|
179
|
+
# each subfolder should have a Report.TXT file
|
180
|
+
# sample_names = []
|
181
|
+
wavelengths = []
|
182
|
+
retention_times = []
|
183
|
+
peak_areas = []
|
184
|
+
|
185
|
+
# Get a list of all items (files and directories) in the folder
|
186
|
+
items = [os.path.join(folder_path, item) for item in os.listdir(folder_path)]
|
187
|
+
|
188
|
+
# Filter only directories from the list
|
189
|
+
# folders = [item for item in items if os.path.isdir(item)]
|
190
|
+
|
191
|
+
# # Sort the folders by creation date
|
192
|
+
# sorted_folders = sorted(folders, key=lambda f: os.stat(f).st_ctime)
|
193
|
+
|
194
|
+
for filename in items:
|
195
|
+
if filename.endswith('Report.TXT'):
|
196
|
+
# file_path = os.path.join(subfolder, filename)
|
197
|
+
file_wavelengths, file_retention_times, file_peak_areas = process_export_report(filename,
|
198
|
+
target_wavelengths,
|
199
|
+
min_retention_time,
|
200
|
+
max_retention_time)
|
201
|
+
wavelengths.extend(file_wavelengths)
|
202
|
+
retention_times.extend(file_retention_times)
|
203
|
+
peak_areas.extend(file_peak_areas)
|
204
|
+
|
205
|
+
results_df = pd.DataFrame({'Wavelengths': wavelengths, 'Retention Times': retention_times, 'Areas': peak_areas})
|
206
|
+
|
207
|
+
# Save the results to a CSV file
|
208
|
+
# results_csv_path = os.path.join(folder_path, 'all_sample_data.csv') # Specify the desired file path
|
209
|
+
# results_df.to_csv(results_csv_path, index=False)
|
210
|
+
# print(f"Results saved to {results_csv_path}")
|
211
|
+
return results_df
|
212
|
+
|
213
|
+
|
214
|
+
def process_csv_report(folder_path: str, num: int) -> Result[List[AgilentPeak], AnyStr]:
|
215
|
+
potential_report = os.path.join(folder_path, f'REPORT0{num}.CSV')
|
216
|
+
if os.path.exists(potential_report):
|
217
|
+
df = pd.read_csv(potential_report, encoding="utf-16", header=None)
|
218
|
+
return Ok(df.apply(lambda row: AgilentPeak(*row), axis=1))
|
219
|
+
return Err("No report found")
|
File without changes
|
@@ -1,11 +1,117 @@
|
|
1
1
|
from ....control.controllers import CommunicationController
|
2
2
|
from .device import DeviceController
|
3
|
-
from ....utils.
|
3
|
+
from ....utils.injector_types import *
|
4
|
+
from ....utils.macro import Command
|
5
|
+
from ....utils.table_types import Table, RegisterFlag
|
4
6
|
|
5
7
|
|
6
8
|
class InjectorController(DeviceController):
|
7
|
-
def get_row(self, row: int):
|
8
|
-
pass
|
9
9
|
|
10
10
|
def __init__(self, controller: CommunicationController, table: Table):
|
11
11
|
super().__init__(controller, table)
|
12
|
+
|
13
|
+
def get_row(self, row: int) -> InjectorFunction:
|
14
|
+
def return_tray_loc() -> Tray:
|
15
|
+
pass
|
16
|
+
|
17
|
+
function = self.get_text(row, RegisterFlag.FUNCTION)
|
18
|
+
if function == "Wait":
|
19
|
+
return Wait(duration=self.get_num(row, RegisterFlag.TIME))
|
20
|
+
elif function == "Inject":
|
21
|
+
return Inject()
|
22
|
+
elif function == "Draw":
|
23
|
+
# TODO: better error handling
|
24
|
+
is_source = SourceType(self.get_text(row, RegisterFlag.DRAW_SOURCE))
|
25
|
+
is_volume = Mode(self.get_text(row, RegisterFlag.DRAW_VOLUME))
|
26
|
+
vol = self.get_num(row, RegisterFlag.DRAW_VOLUME_VALUE) if is_volume == Mode.SET else None
|
27
|
+
if is_source is SourceType.SPECIFIC_LOCATION:
|
28
|
+
return Draw(amount=vol, source=return_tray_loc())
|
29
|
+
elif is_source is SourceType.LOCATION:
|
30
|
+
return Draw(amount=vol, location=self.get_text(row, RegisterFlag.DRAW_LOCATION))
|
31
|
+
elif function == "Remote":
|
32
|
+
return Remote(command=RemoteCommand(self.get_text(row, RegisterFlag.REMOTE)),
|
33
|
+
duration=self.get_num(row, RegisterFlag.REMOTE_DUR))
|
34
|
+
|
35
|
+
def load(self) -> InjectorTable:
|
36
|
+
rows = self.get_num_rows()
|
37
|
+
if rows.is_ok():
|
38
|
+
return InjectorTable(functions=[self.get_row(i) for i in range(int(rows.ok_value.num_response))])
|
39
|
+
|
40
|
+
def edit(self, injector_table: InjectorTable):
|
41
|
+
columns_added = set()
|
42
|
+
|
43
|
+
def add_table_val(col_name: RegisterFlag, val: Union[str, int, float]):
|
44
|
+
nonlocal columns_added
|
45
|
+
if True:
|
46
|
+
if isinstance(val, str):
|
47
|
+
self.edit_row_text(col_name=col_name, val=val)
|
48
|
+
else:
|
49
|
+
self.edit_row_num(col_name=col_name, val=val)
|
50
|
+
else:
|
51
|
+
if isinstance(val, str):
|
52
|
+
self.add_new_col_text(col_name=col_name, val=val)
|
53
|
+
else:
|
54
|
+
self.add_new_col_num(col_name=col_name, val=val)
|
55
|
+
columns_added.add(col_name)
|
56
|
+
|
57
|
+
def add_inject(inject: Inject):
|
58
|
+
add_table_val(col_name=RegisterFlag.FUNCTION, val=inject.__class__.__name__)
|
59
|
+
|
60
|
+
def add_draw(draw: Draw):
|
61
|
+
add_table_val(col_name=RegisterFlag.FUNCTION, val=draw.__class__.__name__)
|
62
|
+
add_table_val(col_name=RegisterFlag.DRAW_SPEED, val=SourceType.DEFAULT.value)
|
63
|
+
add_table_val(col_name=RegisterFlag.DRAW_OFFSET, val=SourceType.DEFAULT.value)
|
64
|
+
|
65
|
+
if draw.amount:
|
66
|
+
add_table_val(col_name=RegisterFlag.DRAW_VOLUME, val=Mode.SET.value)
|
67
|
+
add_table_val(col_name=RegisterFlag.DRAW_VOLUME_VALUE, val=draw.amount)
|
68
|
+
else:
|
69
|
+
add_table_val(col_name=RegisterFlag.DRAW_VOLUME, val=Mode.DEFAULT.value)
|
70
|
+
|
71
|
+
if draw.location:
|
72
|
+
add_table_val(col_name=RegisterFlag.DRAW_SOURCE, val=SourceType.LOCATION.value)
|
73
|
+
add_table_val(col_name=RegisterFlag.DRAW_LOCATION, val=draw.location)
|
74
|
+
elif draw.source:
|
75
|
+
add_table_val(col_name=RegisterFlag.DRAW_SOURCE, val=SourceType.SPECIFIC_LOCATION.value)
|
76
|
+
add_table_val(col_name=RegisterFlag.DRAW_LOCATION_UNIT, val=1)
|
77
|
+
add_table_val(col_name=RegisterFlag.DRAW_LOCATION_TRAY, val=1)
|
78
|
+
add_table_val(col_name=RegisterFlag.DRAW_LOCATION_ROW, val=1)
|
79
|
+
add_table_val(col_name=RegisterFlag.DRAW_LOCATION_COLUMN, val=1)
|
80
|
+
else:
|
81
|
+
add_table_val(col_name=RegisterFlag.DRAW_SOURCE, val=SourceType.DEFAULT.value)
|
82
|
+
|
83
|
+
def add_wait(wait: Wait):
|
84
|
+
add_table_val(col_name=RegisterFlag.FUNCTION, val=wait.__class__.__name__)
|
85
|
+
add_table_val(col_name=RegisterFlag.TIME, val=wait.duration)
|
86
|
+
|
87
|
+
def add_remote(remote: Remote):
|
88
|
+
add_table_val(col_name=RegisterFlag.FUNCTION, val=remote.__class__.__name__)
|
89
|
+
add_table_val(col_name=RegisterFlag.REMOTE, val=remote.command.value)
|
90
|
+
add_table_val(col_name=RegisterFlag.REMOTE_DUR, val=remote.duration)
|
91
|
+
|
92
|
+
self.send(Command.SAVE_METHOD_CMD)
|
93
|
+
rows = self.get_num_rows()
|
94
|
+
if rows.is_ok():
|
95
|
+
existing_row_num = rows.value.num_response
|
96
|
+
for i, function in enumerate(injector_table.functions):
|
97
|
+
if (i+1) > existing_row_num:
|
98
|
+
self.add_row()
|
99
|
+
if isinstance(function, Inject):
|
100
|
+
add_inject(function)
|
101
|
+
elif isinstance(function, Draw):
|
102
|
+
add_draw(function)
|
103
|
+
elif isinstance(function, Wait):
|
104
|
+
add_wait(function)
|
105
|
+
elif isinstance(function, Remote):
|
106
|
+
add_remote(function)
|
107
|
+
self.download()
|
108
|
+
self.send(Command.SAVE_METHOD_CMD)
|
109
|
+
self.send(Command.SWITCH_METHOD_CMD)
|
110
|
+
existing_row_num = self.get_num_rows().ok_value.num_response
|
111
|
+
|
112
|
+
def download(self):
|
113
|
+
self.send('Sleep 1')
|
114
|
+
self.sleepy_send("DownloadRCMethod WLS1")
|
115
|
+
self.send('Sleep 1')
|
116
|
+
self.sleepy_send("DownloadLWls 1")
|
117
|
+
self.send('Sleep 1')
|
@@ -4,6 +4,7 @@ import time
|
|
4
4
|
from xsdata.formats.dataclass.parsers import XmlParser
|
5
5
|
|
6
6
|
from .table import TableController
|
7
|
+
from ..devices.injector import InjectorController
|
7
8
|
from ....control.controllers import CommunicationController
|
8
9
|
from ....generated import PumpMethod, DadMethod, SolventElement
|
9
10
|
from ....utils.chromatogram import TIME_FORMAT, AgilentChannelChromatogramData
|
@@ -17,7 +18,13 @@ class MethodController(TableController):
|
|
17
18
|
Class containing method related logic
|
18
19
|
"""
|
19
20
|
|
20
|
-
def __init__(self, controller: CommunicationController,
|
21
|
+
def __init__(self, controller: CommunicationController,
|
22
|
+
src: str,
|
23
|
+
data_dir: str,
|
24
|
+
table: Table,
|
25
|
+
offline: bool,
|
26
|
+
injector_controller: InjectorController):
|
27
|
+
self.injector_controller = injector_controller
|
21
28
|
super().__init__(controller, src, data_dir, table, offline=offline)
|
22
29
|
|
23
30
|
def check(self) -> str:
|
@@ -310,8 +317,6 @@ class MethodController(TableController):
|
|
310
317
|
|
311
318
|
:param experiment_name: Name of the experiment
|
312
319
|
"""
|
313
|
-
if not self.table_state:
|
314
|
-
self.table_state = self.load()
|
315
320
|
|
316
321
|
folder_name = ""
|
317
322
|
hplc_is_running = False
|
@@ -331,13 +336,17 @@ class MethodController(TableController):
|
|
331
336
|
self.data_files.append(os.path.join(self.data_dir, folder_name))
|
332
337
|
|
333
338
|
if stall_while_running:
|
339
|
+
|
340
|
+
if not self.table_state:
|
341
|
+
self.table_state = self.load()
|
342
|
+
|
334
343
|
run_completed = self.check_hplc_done_running(method=self.table_state)
|
335
344
|
if run_completed.is_ok():
|
336
345
|
self.data_files[-1] = run_completed.ok_value
|
337
346
|
else:
|
338
347
|
raise RuntimeError("Run error has occurred.")
|
339
348
|
else:
|
340
|
-
self.data_files[-1]
|
349
|
+
self.data_files[-1] = self.fuzzy_match_most_recent_folder(folder_name).ok_value
|
341
350
|
|
342
351
|
def retrieve_recent_data_files(self) -> str:
|
343
352
|
return self.data_files[-1]
|
@@ -6,6 +6,7 @@ Authors: Lucy Hao
|
|
6
6
|
|
7
7
|
import abc
|
8
8
|
import os
|
9
|
+
import warnings
|
9
10
|
from dataclasses import dataclass
|
10
11
|
from typing import Union, Optional
|
11
12
|
|
@@ -33,8 +34,8 @@ class ChromData:
|
|
33
34
|
class TableController(abc.ABC):
|
34
35
|
|
35
36
|
def __init__(self, controller: CommunicationController,
|
36
|
-
src: str,
|
37
|
-
data_dir: str,
|
37
|
+
src: Optional[str],
|
38
|
+
data_dir: Optional[str],
|
38
39
|
table: Table,
|
39
40
|
offline: bool = False):
|
40
41
|
self.controller = controller
|
@@ -45,26 +46,27 @@ class TableController(abc.ABC):
|
|
45
46
|
# Initialize row counter for table operations
|
46
47
|
self.send('Local Rows')
|
47
48
|
|
48
|
-
if os.path.isdir(src):
|
49
|
+
if src and os.path.isdir(src):
|
49
50
|
self.src: str = src
|
50
51
|
else:
|
51
|
-
|
52
|
+
warnings.warn(f"dir: {src} not found.")
|
52
53
|
|
53
|
-
if os.path.isdir(data_dir):
|
54
|
+
if data_dir and os.path.isdir(data_dir):
|
54
55
|
self.data_dir: str = data_dir
|
55
56
|
else:
|
56
|
-
|
57
|
-
|
58
|
-
self
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
57
|
+
warnings.warn(f"dir: {data_dir} not found.")
|
58
|
+
|
59
|
+
if hasattr(self, "data_dir"):
|
60
|
+
self.spectra: dict[str, Optional[AgilentHPLCChromatogram]] = {
|
61
|
+
"A": AgilentHPLCChromatogram(self.data_dir),
|
62
|
+
"B": AgilentHPLCChromatogram(self.data_dir),
|
63
|
+
"C": AgilentHPLCChromatogram(self.data_dir),
|
64
|
+
"D": AgilentHPLCChromatogram(self.data_dir),
|
65
|
+
"E": AgilentHPLCChromatogram(self.data_dir),
|
66
|
+
"F": AgilentHPLCChromatogram(self.data_dir),
|
67
|
+
"G": AgilentHPLCChromatogram(self.data_dir),
|
68
|
+
"H": AgilentHPLCChromatogram(self.data_dir),
|
69
|
+
}
|
68
70
|
else:
|
69
71
|
self.spectra: dict[str, Optional[AgilentHPLCChromatogram]] = {
|
70
72
|
"A": AgilentHPLCChromatogram(),
|
@@ -80,8 +82,6 @@ class TableController(abc.ABC):
|
|
80
82
|
|
81
83
|
self.uv = None
|
82
84
|
|
83
|
-
|
84
|
-
|
85
85
|
def receive(self) -> Result[Response, str]:
|
86
86
|
for _ in range(10):
|
87
87
|
try:
|
@@ -107,7 +107,7 @@ class TableController(abc.ABC):
|
|
107
107
|
"""
|
108
108
|
self.send(Command.SLEEP_CMD.value.format(seconds=seconds))
|
109
109
|
|
110
|
-
def get_num(self, row: int, col_name: RegisterFlag) -> float:
|
110
|
+
def get_num(self, row: int, col_name: RegisterFlag) -> Union[int, float]:
|
111
111
|
return self.controller.get_num_val(TableOperation.GET_ROW_VAL.value.format(register=self.table.register,
|
112
112
|
table_name=self.table.name,
|
113
113
|
row=row,
|
pychemstation/control/hplc.py
CHANGED
@@ -6,8 +6,10 @@ Authors: Lucy Hao
|
|
6
6
|
|
7
7
|
from typing import Union, Optional
|
8
8
|
|
9
|
+
from .controllers.devices.injector import InjectorController
|
9
10
|
from ..control.controllers import MethodController, SequenceController, CommunicationController
|
10
11
|
from ..utils.chromatogram import AgilentChannelChromatogramData
|
12
|
+
from ..utils.injector_types import InjectorTable
|
11
13
|
from ..utils.macro import Command, HPLCRunningStatus, HPLCAvailStatus, HPLCErrorStatus, Response
|
12
14
|
from ..utils.method_types import MethodDetails
|
13
15
|
from ..utils.sequence_types import SequenceTable, SequenceEntry
|
@@ -27,8 +29,13 @@ class HPLCController:
|
|
27
29
|
)
|
28
30
|
|
29
31
|
INJECTOR_TABLE = Table(
|
30
|
-
register="
|
31
|
-
name="
|
32
|
+
register="RCWLS1Pretreatment[1]",
|
33
|
+
name="InstructionTable"
|
34
|
+
)
|
35
|
+
|
36
|
+
MSD_TABLE = Table(
|
37
|
+
register="MSACQINFO[1]",
|
38
|
+
name="SprayChamber"
|
32
39
|
)
|
33
40
|
|
34
41
|
def __init__(self,
|
@@ -48,7 +55,9 @@ class HPLCController:
|
|
48
55
|
src=method_dir,
|
49
56
|
data_dir=data_dir,
|
50
57
|
table=self.METHOD_TIMETABLE,
|
51
|
-
offline=offline
|
58
|
+
offline=offline,
|
59
|
+
injector_controller=InjectorController(controller=self.comm,
|
60
|
+
table=self.INJECTOR_TABLE))
|
52
61
|
self.sequence_controller = SequenceController(controller=self.comm,
|
53
62
|
src=sequence_dir,
|
54
63
|
data_dir=data_dir,
|
@@ -176,6 +185,9 @@ class HPLCController:
|
|
176
185
|
"""
|
177
186
|
return self.method_controller.check()
|
178
187
|
|
188
|
+
def load_injector_program(self) -> InjectorTable:
|
189
|
+
return self.method_controller.injector_controller.load()
|
190
|
+
|
179
191
|
def load_method(self) -> MethodDetails:
|
180
192
|
"""
|
181
193
|
Returns all details of the currently loaded method, including its timetable.
|
@@ -1,20 +1,31 @@
|
|
1
1
|
from dataclasses import dataclass
|
2
|
-
from
|
2
|
+
from enum import Enum
|
3
|
+
from typing import Union, Optional
|
3
4
|
|
4
5
|
from pychemstation.utils.tray_types import Tray
|
5
6
|
|
6
7
|
|
8
|
+
class SourceType(Enum):
|
9
|
+
DEFAULT = "ActualPosition"
|
10
|
+
SPECIFIC_LOCATION = "ActualPositionPlusLocation"
|
11
|
+
LOCATION = "Location"
|
12
|
+
|
13
|
+
|
14
|
+
class Mode(Enum):
|
15
|
+
DEFAULT = "Default"
|
16
|
+
SET = "Set"
|
17
|
+
|
18
|
+
|
7
19
|
@dataclass
|
8
20
|
class Draw:
|
9
|
-
amount: float
|
10
|
-
|
11
|
-
|
12
|
-
offset: Any
|
21
|
+
amount: Optional[float] = None
|
22
|
+
location: Optional[str] = None
|
23
|
+
source: Optional[Tray] = None
|
13
24
|
|
14
25
|
|
15
26
|
@dataclass
|
16
27
|
class Wait:
|
17
|
-
|
28
|
+
duration: int
|
18
29
|
|
19
30
|
|
20
31
|
@dataclass
|
@@ -22,7 +33,18 @@ class Inject:
|
|
22
33
|
pass
|
23
34
|
|
24
35
|
|
25
|
-
|
36
|
+
class RemoteCommand(Enum):
|
37
|
+
START = "START"
|
38
|
+
PREPARE = "PREPARE"
|
39
|
+
|
40
|
+
|
41
|
+
@dataclass
|
42
|
+
class Remote:
|
43
|
+
command: RemoteCommand
|
44
|
+
duration: int
|
45
|
+
|
46
|
+
|
47
|
+
InjectorFunction = Union[Draw, Wait, Inject, Remote]
|
26
48
|
|
27
49
|
|
28
50
|
@dataclass
|
pychemstation/utils/macro.py
CHANGED
@@ -37,7 +37,7 @@ class Command(Enum):
|
|
37
37
|
# Method and Sequence Related
|
38
38
|
GET_METHOD_CMD = "response$ = _MethFile$"
|
39
39
|
GET_ROWS_CMD = 'response_num = TabHdrVal({register}, "{table_name}", "{col_name}")'
|
40
|
-
SWITCH_METHOD_CMD = 'LoadMethod
|
40
|
+
SWITCH_METHOD_CMD = 'LoadMethod _MethPath$, _MethFile$'
|
41
41
|
START_METHOD_CMD = "StartMethod"
|
42
42
|
RUN_METHOD_CMD = 'RunMethod "{data_dir}",, "{experiment_name}_{timestamp}"'
|
43
43
|
STOP_METHOD_CMD = "StopMethod"
|
@@ -4,6 +4,7 @@ from dataclasses import dataclass
|
|
4
4
|
from enum import Enum
|
5
5
|
from typing import Union, Any, Optional
|
6
6
|
|
7
|
+
from .injector_types import InjectorTable
|
7
8
|
from .table_types import RegisterFlag
|
8
9
|
from ..generated import Signal
|
9
10
|
|
@@ -36,7 +37,7 @@ class TimeTableEntry:
|
|
36
37
|
|
37
38
|
@dataclass
|
38
39
|
class MethodDetails:
|
39
|
-
"""An Agilent Chemstation method, TODO is to add MS parameters
|
40
|
+
"""An Agilent Chemstation method, TODO is to add MS parameters, injector parameters
|
40
41
|
|
41
42
|
:attribute name: the name of the method, should be the same as the Chemstation method name.
|
42
43
|
:attribute timetable: list of entries in the method timetable
|
@@ -49,6 +50,7 @@ class MethodDetails:
|
|
49
50
|
name: str
|
50
51
|
params: HPLCMethodParams
|
51
52
|
timetable: list[TimeTableEntry]
|
53
|
+
injector_program: Optional[InjectorTable] = None
|
52
54
|
stop_time: Optional[int] = None
|
53
55
|
post_time: Optional[int] = None
|
54
56
|
dad_wavelengthes: Optional[list[Signal]] = None
|
@@ -65,6 +65,26 @@ class RegisterFlag(Enum):
|
|
65
65
|
SAMPLE_TYPE = "SampleType"
|
66
66
|
DATA_FILE = "DataFileName"
|
67
67
|
|
68
|
+
# for Injector Table
|
69
|
+
## Draw
|
70
|
+
DRAW_SOURCE = "DrawSource"
|
71
|
+
DRAW_VOLUME = "DrawVolume_Mode"
|
72
|
+
DRAW_SPEED = "DrawSpeed_Mode"
|
73
|
+
DRAW_OFFSET = "DrawOffset_Mode"
|
74
|
+
# SetObjHdrVal RCWLS1Pretreatment[1], "DrawVolume_Value", 1
|
75
|
+
DRAW_VOLUME_VALUE = "DrawVolume_Value"
|
76
|
+
DRAW_LOCATION = "DrawLocation"
|
77
|
+
DRAW_LOCATION_TRAY = "DrawLocationPlus_Tray"
|
78
|
+
DRAW_LOCATION_UNIT = "DrawLocationPlus_Unit"
|
79
|
+
DRAW_LOCATION_ROW = "DrawLocationPlus_Row"
|
80
|
+
DRAW_LOCATION_COLUMN = "DrawLocationPlus_Column"
|
81
|
+
## Inject
|
82
|
+
## Wait
|
83
|
+
## Remote
|
84
|
+
REMOTE = "RemoteLine"
|
85
|
+
REMOTE_DUR = "RemoteDuration"
|
86
|
+
|
87
|
+
|
68
88
|
|
69
89
|
@dataclass
|
70
90
|
class Table:
|
@@ -1,11 +1,12 @@
|
|
1
1
|
pychemstation/__init__.py,sha256=SpTl-Tg1B1HTyjNOE-8ue-N2wGnXN_2zl7RFUSxlkiM,33
|
2
2
|
pychemstation/analysis/__init__.py,sha256=EWoU47iyn9xGS-b44zK9eq50bSjOV4AC5dvt420YMI4,44
|
3
3
|
pychemstation/analysis/base_spectrum.py,sha256=XPf9eJ72uz0CnxCY5uFOyu1MbVX-OTTXeN1tLzIMok4,16536
|
4
|
+
pychemstation/analysis/process_report.py,sha256=d290KgPY-cMlQg4yHaspLFxgso_yu9qNxXG6SF2qpuo,9054
|
4
5
|
pychemstation/analysis/spec_utils.py,sha256=UOo9hJR3evJfmaohEEsyb7aq6X996ofuUfu-GKjiDi8,10201
|
5
6
|
pychemstation/analysis/utils.py,sha256=ISupAOb_yqA4_DZRK9v18UL-XjUQccAicIJKb1VMnGg,2055
|
6
7
|
pychemstation/control/__init__.py,sha256=4xTy8X-mkn_PPZKr7w9rnj1wZhtmTesbQptPhpYmKXs,64
|
7
8
|
pychemstation/control/comm.py,sha256=u44g1hTluQ0yUG93Un-QAshScoDpgYRrZfFTgweP5tY,7386
|
8
|
-
pychemstation/control/hplc.py,sha256=
|
9
|
+
pychemstation/control/hplc.py,sha256=LkNB_wKNaW3pU-OZlYfwFbXGWU2Iwmr1WD5c3dCWEbY,9742
|
9
10
|
pychemstation/control/controllers/__init__.py,sha256=EM6LBNSTJqYVatmnvPq0P-S3q0POA88c-y64zL79I_I,252
|
10
11
|
pychemstation/control/controllers/comm.py,sha256=IU4I_Q42VNCNUlVi93MxCmw2EBY9hiBDkU9FxubKg3c,7441
|
11
12
|
pychemstation/control/controllers/method.py,sha256=XUclB7lQ_SIkquR58MBmmi9drHIPEq9AR8VprTLenvI,15503
|
@@ -13,14 +14,15 @@ pychemstation/control/controllers/sequence.py,sha256=kYNxxck2I-q9mZDEZwG8bJ_99Ff
|
|
13
14
|
pychemstation/control/controllers/table_controller.py,sha256=70ovnIjLKkJborS1ztk445Mv42TtUM9jUniaQmZuyWQ,11031
|
14
15
|
pychemstation/control/controllers/devices/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
15
16
|
pychemstation/control/controllers/devices/column.py,sha256=SCpCnVFZFUM9LM51MbWkVcBRayN3WFxy7lz9gs2PYeY,348
|
17
|
+
pychemstation/control/controllers/devices/dad.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
16
18
|
pychemstation/control/controllers/devices/device.py,sha256=SF1JK93FjmACnYrlKvldX3gEeA21qnXZegeNhc9QJGQ,738
|
17
|
-
pychemstation/control/controllers/devices/injector.py,sha256=
|
19
|
+
pychemstation/control/controllers/devices/injector.py,sha256=1iZgPQYw6AcV1VKw0RG-k94czE8lCRVWx5NCCubIOZA,5516
|
18
20
|
pychemstation/control/controllers/devices/pump.py,sha256=DJQh4lNXEraeC1CWrsKmsITOjuYlRI3tih_XRB3F1hg,1404
|
19
21
|
pychemstation/control/controllers/tables/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
20
|
-
pychemstation/control/controllers/tables/method.py,sha256=
|
22
|
+
pychemstation/control/controllers/tables/method.py,sha256=3GdAQ6Cwf20QL3v7eMkwNieWbJdtr9GN12USbSVl_iE,16426
|
21
23
|
pychemstation/control/controllers/tables/ms.py,sha256=JFD-tOhu8uRyKdl-E3-neRssii8MNqVRIlsrnFhNY_M,682
|
22
24
|
pychemstation/control/controllers/tables/sequence.py,sha256=vqwJeV38YWdFnaDXvZVOGYl-UCV9lmMbh8Fj5kQ3mqY,8815
|
23
|
-
pychemstation/control/controllers/tables/table.py,sha256=
|
25
|
+
pychemstation/control/controllers/tables/table.py,sha256=J-uNIFHVznPJqOKPmmqrJBXt70KlxmZlSdtEVM2pEKM,12576
|
24
26
|
pychemstation/control/table/__init__.py,sha256=RgMN4uIWHdNUHpGRBWdzmzAbk7XEKl6Y-qtqWCxzSZU,124
|
25
27
|
pychemstation/control/table/method.py,sha256=THVoGomSXff_CTU3eAYme0BYwkPzab5UgZKsiZ29QSk,12196
|
26
28
|
pychemstation/control/table/sequence.py,sha256=Eri52AnbE3BGthfrRSvYKYciquUzvHKo0lYUTySYYE8,10542
|
@@ -30,23 +32,24 @@ pychemstation/generated/dad_method.py,sha256=0W8Z5WDtF5jpIcudMqb7XrkTnR2EGg_QOCs
|
|
30
32
|
pychemstation/generated/pump_method.py,sha256=sUhE2Oo00nzVcoONtq3EMWsN4wLSryXbG8f3EeViWKg,12174
|
31
33
|
pychemstation/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
32
34
|
pychemstation/utils/chromatogram.py,sha256=-q3_hL9GTyi4C95os7IwAiOrkTM4EXIiigm-nW9pFmM,3221
|
33
|
-
pychemstation/utils/injector_types.py,sha256=
|
34
|
-
pychemstation/utils/macro.py,sha256=
|
35
|
-
pychemstation/utils/method_types.py,sha256=
|
35
|
+
pychemstation/utils/injector_types.py,sha256=SD452SwEHNx4Xs2p-mhg6X0pd99XewQ1Zbu-r9kPOJs,817
|
36
|
+
pychemstation/utils/macro.py,sha256=o1dypIKhEMbDea34VFh4gKu-kWIjXZAFyqK4FYjCKjo,2836
|
37
|
+
pychemstation/utils/method_types.py,sha256=3qxKeREl_97GnQ74qcA3kxibnvWI4ueb-6XZlxcV2Hg,1632
|
36
38
|
pychemstation/utils/parsing.py,sha256=bnFIsZZwFy9NKzVUf517yN-ogzQbm0hp_aho3KUD6Is,9317
|
37
39
|
pychemstation/utils/pump_types.py,sha256=HWQHxscGn19NTrfYBwQRCO2VcYfwyko7YfBO5uDhEm4,93
|
38
40
|
pychemstation/utils/sequence_types.py,sha256=4cNpmRdPLN5oGN7ozHgT21E65aBO8vV3ZcRXMOQ3EA8,1084
|
39
|
-
pychemstation/utils/table_types.py,sha256=
|
41
|
+
pychemstation/utils/table_types.py,sha256=0kg7gZXFk7O5l0K1BEBaF4OFFdja3-hFUG9UbN5PBcs,3173
|
40
42
|
pychemstation/utils/tray_types.py,sha256=MaHN36rhcEI5mAY95VU8hfP9HhAlngQvMYq-2oyC0hc,764
|
41
43
|
tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
42
|
-
tests/constants.py,sha256=
|
43
|
-
tests/test_comb.py,sha256=
|
44
|
-
tests/test_comm.py,sha256=
|
45
|
-
tests/test_inj.py,sha256=
|
46
|
-
tests/test_method.py,sha256=
|
47
|
-
tests/
|
48
|
-
|
49
|
-
pychemstation-0.
|
50
|
-
pychemstation-0.
|
51
|
-
pychemstation-0.
|
52
|
-
pychemstation-0.
|
44
|
+
tests/constants.py,sha256=55DOLpylLt12mb_gSgzEo-EYynwTmI2uH7PcrTM6Iq0,2455
|
45
|
+
tests/test_comb.py,sha256=TS-CbtiPbntL4u6E1gSZ6xquNp6cQxIFdJqUr2ak7PA,5515
|
46
|
+
tests/test_comm.py,sha256=iwl-Ey-xoytXmlNrjG84pDm82Ry_QUX6wY4gmVh4NDc,2516
|
47
|
+
tests/test_inj.py,sha256=Blpk-z9PQuqo4xQ7AUi0CS2czMiYm-pqZe75OFTXru4,1092
|
48
|
+
tests/test_method.py,sha256=KB7yAtVb4gZftnYzh-VfPb9LGVZOHUIW6OljEYRtbhA,4570
|
49
|
+
tests/test_proc_rep.py,sha256=WhUiFqDD1Aey_Nc6Hvbd2zo48K4MWjwDhfO9LiwEQ7M,703
|
50
|
+
tests/test_sequence.py,sha256=vs5-dqkItRds_tPM2-N6MNJ37FB0nLRFaDzBV8d42i8,4880
|
51
|
+
pychemstation-0.6.0.dist-info/LICENSE,sha256=9bdF75gIf1MecZ7oymqWgJREVz7McXPG-mjqrTmzzD8,18658
|
52
|
+
pychemstation-0.6.0.dist-info/METADATA,sha256=mO3-TN1CbOOEDxaUfAdwfZvRE65V3IvlXecYdb0uQBE,4370
|
53
|
+
pychemstation-0.6.0.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
54
|
+
pychemstation-0.6.0.dist-info/top_level.txt,sha256=zXfKu_4nYWwPHo3OsuhshMNC3SPkcoTGCyODjURaghY,20
|
55
|
+
pychemstation-0.6.0.dist-info/RECORD,,
|
tests/constants.py
CHANGED
@@ -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 = "hplc_testing"
|
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\\"
|
tests/test_comb.py
CHANGED
tests/test_comm.py
CHANGED
tests/test_inj.py
CHANGED
@@ -17,22 +17,17 @@ class TestInj(unittest.TestCase):
|
|
17
17
|
method_dir=path_constants[1],
|
18
18
|
data_dir=path_constants[2],
|
19
19
|
sequence_dir=path_constants[3])
|
20
|
+
# self.hplc_controller.switch_method(DEFAULT_METHOD)
|
20
21
|
|
21
22
|
def test_load_inj(self):
|
22
|
-
self.hplc_controller.switch_method(DEFAULT_METHOD)
|
23
23
|
try:
|
24
|
-
|
25
|
-
self.assertTrue(
|
24
|
+
inj_table = self.hplc_controller.load_injector_program()
|
25
|
+
self.assertTrue(len(inj_table.functions) == 2)
|
26
26
|
except Exception as e:
|
27
27
|
self.fail(f"Should have not failed, {e}")
|
28
28
|
|
29
|
-
|
30
|
-
|
31
|
-
new_method = gen_rand_method()
|
32
|
-
try:
|
33
|
-
self.hplc_controller.edit_method(new_method)
|
34
|
-
except Exception as e:
|
35
|
-
self.fail(f"Should have not failed: {e}")
|
29
|
+
|
30
|
+
|
36
31
|
|
37
32
|
if __name__ == '__main__':
|
38
33
|
unittest.main()
|
tests/test_method.py
CHANGED
@@ -28,7 +28,25 @@ class TestMethod(unittest.TestCase):
|
|
28
28
|
|
29
29
|
def test_edit_method(self):
|
30
30
|
self.hplc_controller.method_controller.switch(DEFAULT_METHOD)
|
31
|
-
new_method =
|
31
|
+
new_method = MethodDetails(name=DEFAULT_METHOD,
|
32
|
+
timetable=[TimeTableEntry(start_time=1,
|
33
|
+
organic_modifer=20,
|
34
|
+
flow=0.65),
|
35
|
+
TimeTableEntry(start_time=2,
|
36
|
+
organic_modifer=30,
|
37
|
+
flow=0.65),
|
38
|
+
TimeTableEntry(start_time=2.5,
|
39
|
+
organic_modifer=60,
|
40
|
+
flow=0.65),
|
41
|
+
TimeTableEntry(start_time=3,
|
42
|
+
organic_modifer=80,
|
43
|
+
flow=0.65),
|
44
|
+
TimeTableEntry(start_time=3.5,
|
45
|
+
organic_modifer=100,
|
46
|
+
flow=0.65)],
|
47
|
+
stop_time=4,
|
48
|
+
post_time=1,
|
49
|
+
params=HPLCMethodParams(organic_modifier=5, flow=0.65))
|
32
50
|
try:
|
33
51
|
self.hplc_controller.edit_method(new_method)
|
34
52
|
except Exception as e:
|
tests/test_proc_rep.py
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
import unittest
|
2
|
+
|
3
|
+
from result import Result
|
4
|
+
|
5
|
+
from pychemstation.analysis.process_report import process_csv_report
|
6
|
+
|
7
|
+
|
8
|
+
class TestReport(unittest.TestCase):
|
9
|
+
|
10
|
+
def test_process_reporttxt(self):
|
11
|
+
try:
|
12
|
+
# TODO
|
13
|
+
print('yes')
|
14
|
+
except Exception as e:
|
15
|
+
self.fail(f"Should have not failed, {e}")
|
16
|
+
|
17
|
+
def test_report_csv(self):
|
18
|
+
try:
|
19
|
+
possible_peaks: Result = process_csv_report(folder_path="0_2025-03-15 19-14-35.D", num=1)
|
20
|
+
self.assertTrue(len(possible_peaks.ok_value) == 16)
|
21
|
+
print('yes')
|
22
|
+
except Exception as e:
|
23
|
+
self.fail(f"Should have not failed: {e}")
|
24
|
+
|
25
|
+
|
26
|
+
if __name__ == '__main__':
|
27
|
+
unittest.main()
|
tests/test_sequence.py
CHANGED
@@ -2,13 +2,12 @@ import os
|
|
2
2
|
import unittest
|
3
3
|
|
4
4
|
from pychemstation.control import HPLCController
|
5
|
-
from pychemstation.utils.sequence_types import *
|
6
5
|
from tests.constants import *
|
7
6
|
|
8
7
|
|
9
8
|
class TestSequence(unittest.TestCase):
|
10
9
|
def setUp(self):
|
11
|
-
path_constants = room(
|
10
|
+
path_constants = room(242)
|
12
11
|
for path in path_constants:
|
13
12
|
if not os.path.exists(path):
|
14
13
|
self.fail(
|
File without changes
|
File without changes
|
File without changes
|