pychemstation 0.10.2__py3-none-any.whl → 0.10.4__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.
Files changed (31) hide show
  1. pychemstation/__init__.py +1 -1
  2. pychemstation/analysis/__init__.py +3 -4
  3. pychemstation/analysis/base_spectrum.py +7 -7
  4. pychemstation/{utils → analysis}/chromatogram.py +4 -4
  5. pychemstation/analysis/process_report.py +106 -70
  6. pychemstation/control/README.md +21 -53
  7. pychemstation/control/__init__.py +3 -2
  8. pychemstation/control/controllers/__init__.py +1 -5
  9. pychemstation/control/controllers/comm.py +20 -11
  10. pychemstation/control/controllers/devices/device.py +22 -12
  11. pychemstation/control/controllers/devices/injector.py +24 -14
  12. pychemstation/control/controllers/tables/method.py +233 -100
  13. pychemstation/control/controllers/tables/ms.py +7 -4
  14. pychemstation/control/controllers/tables/sequence.py +134 -54
  15. pychemstation/control/controllers/tables/table.py +152 -92
  16. pychemstation/control/hplc.py +96 -78
  17. pychemstation/generated/__init__.py +0 -2
  18. pychemstation/generated/pump_method.py +15 -19
  19. pychemstation/utils/macro.py +10 -9
  20. pychemstation/utils/method_types.py +1 -0
  21. pychemstation/utils/num_utils.py +2 -2
  22. pychemstation/utils/parsing.py +0 -11
  23. pychemstation/utils/sequence_types.py +2 -3
  24. pychemstation/utils/spec_utils.py +2 -3
  25. pychemstation/utils/table_types.py +10 -9
  26. pychemstation/utils/tray_types.py +48 -38
  27. {pychemstation-0.10.2.dist-info → pychemstation-0.10.4.dist-info}/METADATA +46 -20
  28. pychemstation-0.10.4.dist-info/RECORD +37 -0
  29. pychemstation-0.10.2.dist-info/RECORD +0 -37
  30. {pychemstation-0.10.2.dist-info → pychemstation-0.10.4.dist-info}/WHEEL +0 -0
  31. {pychemstation-0.10.2.dist-info → pychemstation-0.10.4.dist-info}/licenses/LICENSE +0 -0
@@ -1,5 +1,6 @@
1
1
  import os
2
2
  import time
3
+ import warnings
3
4
  from typing import Dict, List, Optional
4
5
 
5
6
  from result import Err, Ok, Result
@@ -7,7 +8,7 @@ from typing_extensions import override
7
8
 
8
9
  from ....analysis.process_report import AgilentReport, ReportType
9
10
  from ....control.controllers.comm import CommunicationController
10
- from ....utils.chromatogram import (
11
+ from pychemstation.analysis.chromatogram import (
11
12
  SEQUENCE_TIME_FORMAT,
12
13
  AgilentChannelChromatogramData,
13
14
  AgilentHPLCChromatogram,
@@ -31,15 +32,24 @@ class SequenceController(TableController):
31
32
  Class containing sequence related logic
32
33
  """
33
34
 
34
- def __init__(self, controller: CommunicationController,
35
- method_controller: MethodController,
36
- src: str,
37
- data_dirs: List[str],
38
- table: Table,
39
- offline: bool):
35
+ def __init__(
36
+ self,
37
+ controller: CommunicationController,
38
+ method_controller: MethodController,
39
+ src: str,
40
+ data_dirs: List[str],
41
+ table: Table,
42
+ offline: bool,
43
+ ):
40
44
  self.method_controller = method_controller
41
45
  self.data_files: List[SequenceDataFiles] = []
42
- super().__init__(controller=controller, src=src, data_dirs=data_dirs, table=table, offline=offline)
46
+ super().__init__(
47
+ controller=controller,
48
+ src=src,
49
+ data_dirs=data_dirs,
50
+ table=table,
51
+ offline=offline,
52
+ )
43
53
 
44
54
  def load(self) -> SequenceTable:
45
55
  rows = self.get_num_rows()
@@ -49,7 +59,10 @@ class SequenceController(TableController):
49
59
  if rows.is_ok() and seq_name.is_ok():
50
60
  self.table_state = SequenceTable(
51
61
  name=seq_name.ok_value.string_response.partition(".S")[0],
52
- rows=[self.get_row(r + 1) for r in range(int(rows.ok_value.num_response))])
62
+ rows=[
63
+ self.get_row(r + 1) for r in range(int(rows.ok_value.num_response))
64
+ ],
65
+ )
53
66
  return self.table_state
54
67
  raise RuntimeError(rows.err_value)
55
68
 
@@ -61,15 +74,20 @@ class SequenceController(TableController):
61
74
  inj_vol = float(self.get_text(row, RegisterFlag.INJ_VOL))
62
75
  inj_source = InjectionSource(self.get_text(row, RegisterFlag.INJ_SOR))
63
76
  sample_type = SampleType(self.get_num(row, RegisterFlag.SAMPLE_TYPE))
64
- vial_enum = TenVialColumn(vial_location) if vial_location <= 10 else FiftyFourVialPlate.from_int(
65
- num=vial_location)
66
- return SequenceEntry(sample_name=sample_name,
67
- vial_location=vial_enum,
68
- method=None if len(method) == 0 else method,
69
- num_inj=num_inj,
70
- inj_vol=inj_vol,
71
- inj_source=inj_source,
72
- sample_type=sample_type)
77
+ vial_enum = (
78
+ TenVialColumn(vial_location)
79
+ if vial_location <= 10
80
+ else FiftyFourVialPlate.from_int(num=vial_location)
81
+ )
82
+ return SequenceEntry(
83
+ sample_name=sample_name,
84
+ vial_location=vial_enum,
85
+ method=None if len(method) == 0 else method,
86
+ num_inj=num_inj,
87
+ inj_vol=inj_vol,
88
+ inj_source=inj_source,
89
+ sample_type=sample_type,
90
+ )
73
91
 
74
92
  def check(self) -> str:
75
93
  time.sleep(2)
@@ -143,7 +161,9 @@ class SequenceController(TableController):
143
161
  loc = row.vial_location.value
144
162
  elif isinstance(loc, FiftyFourVialPlate):
145
163
  loc = row.vial_location.value()
146
- self._edit_row_num(row=row_num, col_name=RegisterFlag.VIAL_LOCATION, val=loc)
164
+ self._edit_row_num(
165
+ row=row_num, col_name=RegisterFlag.VIAL_LOCATION, val=loc
166
+ )
147
167
  if row.method:
148
168
  method_dir = self.method_controller.src
149
169
  possible_path = os.path.join(method_dir, row.method) + ".M\\"
@@ -152,19 +172,35 @@ class SequenceController(TableController):
152
172
  method = os.path.join(method_dir, row.method)
153
173
  self._edit_row_text(row=row_num, col_name=RegisterFlag.METHOD, val=method)
154
174
  if row.num_inj:
155
- self._edit_row_num(row=row_num, col_name=RegisterFlag.NUM_INJ, val=row.num_inj)
175
+ self._edit_row_num(
176
+ row=row_num, col_name=RegisterFlag.NUM_INJ, val=row.num_inj
177
+ )
156
178
  if row.inj_vol:
157
- self._edit_row_text(row=row_num, col_name=RegisterFlag.INJ_VOL, val=row.inj_vol)
179
+ self._edit_row_text(
180
+ row=row_num, col_name=RegisterFlag.INJ_VOL, val=row.inj_vol
181
+ )
158
182
  if row.inj_source:
159
- self._edit_row_text(row=row_num, col_name=RegisterFlag.INJ_SOR, val=row.inj_source.value)
183
+ self._edit_row_text(
184
+ row=row_num, col_name=RegisterFlag.INJ_SOR, val=row.inj_source.value
185
+ )
160
186
  if row.sample_name:
161
- self._edit_row_text(row=row_num, col_name=RegisterFlag.NAME, val=row.sample_name)
187
+ self._edit_row_text(
188
+ row=row_num, col_name=RegisterFlag.NAME, val=row.sample_name
189
+ )
162
190
  if row.data_file:
163
- self._edit_row_text(row=row_num, col_name=RegisterFlag.DATA_FILE, val=row.data_file)
191
+ self._edit_row_text(
192
+ row=row_num, col_name=RegisterFlag.DATA_FILE, val=row.data_file
193
+ )
164
194
  else:
165
- self._edit_row_text(row=row_num, col_name=RegisterFlag.DATA_FILE, val=row.sample_name)
195
+ self._edit_row_text(
196
+ row=row_num, col_name=RegisterFlag.DATA_FILE, val=row.sample_name
197
+ )
166
198
  if row.sample_type:
167
- self._edit_row_num(row=row_num, col_name=RegisterFlag.SAMPLE_TYPE, val=row.sample_type.value)
199
+ self._edit_row_num(
200
+ row=row_num,
201
+ col_name=RegisterFlag.SAMPLE_TYPE,
202
+ val=row.sample_type.value,
203
+ )
168
204
 
169
205
  self.send(Command.SAVE_SEQUENCE_CMD)
170
206
 
@@ -187,9 +223,12 @@ class SequenceController(TableController):
187
223
  method_path = entry.method.split(sep="\\")
188
224
  method_name = method_path[-1]
189
225
  if loaded_method != method_name:
190
- method_dir = "\\".join(method_path[:-1])+"\\" if len(method_path) > 1 else None
191
- self.method_controller.switch(method_name=method_name,
192
- alt_method_dir=method_dir)
226
+ method_dir = (
227
+ "\\".join(method_path[:-1]) + "\\" if len(method_path) > 1 else None
228
+ )
229
+ self.method_controller.switch(
230
+ method_name=method_name, alt_method_dir=method_dir
231
+ )
193
232
  curr_method_runtime = self.method_controller.get_total_runtime()
194
233
  total_runtime += curr_method_runtime
195
234
 
@@ -199,7 +238,9 @@ class SequenceController(TableController):
199
238
 
200
239
  if self.check_hplc_is_running():
201
240
  folder_name = f"{self.table_state.name} {timestamp}"
202
- data_file = SequenceDataFiles(dir=folder_name, sequence_name=self.table_state.name)
241
+ data_file = SequenceDataFiles(
242
+ dir=folder_name, sequence_name=self.table_state.name
243
+ )
203
244
  self.data_files.append(data_file)
204
245
 
205
246
  if stall_while_running:
@@ -207,24 +248,33 @@ class SequenceController(TableController):
207
248
  if run_completed.is_ok():
208
249
  self.data_files[-1] = run_completed.ok_value
209
250
  else:
210
- raise RuntimeError("Run error has occurred.")
251
+ warnings.warn("Run may have not completed.")
211
252
  else:
212
253
  raise RuntimeError("Sequence run did not start.")
213
254
 
214
255
  @override
215
- def fuzzy_match_most_recent_folder(self, most_recent_folder: SequenceDataFiles) -> Result[SequenceDataFiles, str]:
256
+ def fuzzy_match_most_recent_folder(
257
+ self, most_recent_folder: SequenceDataFiles
258
+ ) -> Result[SequenceDataFiles, str]:
216
259
  if os.path.isdir(most_recent_folder.dir):
217
260
  subdirs = [x[0] for x in os.walk(most_recent_folder.dir)]
218
- potential_folders = sorted(list(filter(lambda d: most_recent_folder.dir in d, subdirs)))
219
- most_recent_folder.child_dirs = [f for f in potential_folders if
220
- most_recent_folder.dir in f and ".M" not in f and ".D" in f]
261
+ potential_folders = sorted(
262
+ list(filter(lambda d: most_recent_folder.dir in d, subdirs))
263
+ )
264
+ most_recent_folder.child_dirs = [
265
+ f
266
+ for f in potential_folders
267
+ if most_recent_folder.dir in f and ".M" not in f and ".D" in f
268
+ ]
221
269
  return Ok(most_recent_folder)
222
270
 
223
271
  try:
224
272
  potential_folders = []
225
273
  for d in self.data_dirs:
226
274
  subdirs = [x[0] for x in os.walk(d)]
227
- potential_folders = sorted(list(filter(lambda d: most_recent_folder.dir in d, subdirs)))
275
+ potential_folders = sorted(
276
+ list(filter(lambda d: most_recent_folder.dir in d, subdirs))
277
+ )
228
278
  if len(potential_folders) > 0:
229
279
  break
230
280
  assert len(potential_folders) > 0
@@ -239,49 +289,79 @@ class SequenceController(TableController):
239
289
  potential_folders = []
240
290
  for d in self.data_dirs:
241
291
  subdirs = [x[0] for x in os.walk(d)]
242
- potential_folders = sorted(list(filter(lambda d: parent_dir in d, subdirs)))
292
+ potential_folders = sorted(
293
+ list(filter(lambda d: parent_dir in d, subdirs))
294
+ )
243
295
  if len(potential_folders) > 0:
244
296
  break
245
297
  assert len(potential_folders) > 0
246
- most_recent_folder.child_dirs = [f for f in potential_folders if
247
- parent_dir in f and ".M" not in f and ".D" in f]
298
+ most_recent_folder.child_dirs = [
299
+ f
300
+ for f in potential_folders
301
+ if parent_dir in f and ".M" not in f and ".D" in f
302
+ ]
248
303
  return Ok(most_recent_folder)
249
- except Exception:
250
- return Err("Failed to get sequence folder")
304
+ except Exception as e:
305
+ error = f"Failed to get sequence folder: {e}"
306
+ return Err(error)
251
307
 
252
- def get_data_uv(self,custom_path: Optional[str] = None) -> List[Dict[str, AgilentHPLCChromatogram]]:
253
- custom_path = SequenceDataFiles(dir=custom_path, child_dirs=[], sequence_name="") if custom_path else self.data_files[-1]
308
+ def get_data_uv(
309
+ self, custom_path: Optional[str] = None
310
+ ) -> List[Dict[int, AgilentHPLCChromatogram]]:
311
+ custom_path = (
312
+ SequenceDataFiles(dir=custom_path, child_dirs=[], sequence_name="")
313
+ if custom_path
314
+ else self.data_files[-1]
315
+ )
254
316
  if len(custom_path.child_dirs) == 0:
255
- self.data_files[-1] = self.fuzzy_match_most_recent_folder(custom_path).ok_value
256
- all_w_spectra: List[Dict[str, AgilentHPLCChromatogram]] = []
317
+ self.data_files[-1] = self.fuzzy_match_most_recent_folder(
318
+ custom_path
319
+ ).ok_value
320
+ all_w_spectra: List[Dict[int, AgilentHPLCChromatogram]] = []
257
321
  for row in self.data_files[-1].child_dirs:
258
322
  self.get_uv_spectrum(row)
259
323
  all_w_spectra.append(self.uv)
260
324
  return all_w_spectra
261
325
 
262
- def get_data(self, custom_path: Optional[str] = None) -> List[AgilentChannelChromatogramData]:
263
- custom_path = SequenceDataFiles(dir=custom_path, child_dirs=[], sequence_name="") if custom_path else self.data_files[-1]
326
+ def get_data(
327
+ self, custom_path: Optional[str] = None
328
+ ) -> List[AgilentChannelChromatogramData]:
329
+ custom_path = (
330
+ SequenceDataFiles(dir=custom_path, child_dirs=[], sequence_name="")
331
+ if custom_path
332
+ else self.data_files[-1]
333
+ )
264
334
  if len(custom_path.child_dirs) == 0:
265
- self.data_files[-1] = self.fuzzy_match_most_recent_folder(custom_path).ok_value
335
+ self.data_files[-1] = self.fuzzy_match_most_recent_folder(
336
+ custom_path
337
+ ).ok_value
266
338
  spectra: List[AgilentChannelChromatogramData] = []
267
339
  for row in self.data_files[-1].child_dirs:
268
340
  self.get_spectrum_at_channels(row)
269
341
  spectra.append(AgilentChannelChromatogramData(**self.spectra))
270
342
  return spectra
271
343
 
272
- def get_report(self, custom_path: Optional[str] = None,
273
- report_type: ReportType = ReportType.TXT) -> List[AgilentReport]:
344
+ def get_report(
345
+ self,
346
+ custom_path: Optional[str] = None,
347
+ report_type: ReportType = ReportType.TXT,
348
+ ) -> List[AgilentReport]:
274
349
  if custom_path:
275
350
  self.data_files.append(
276
- self.fuzzy_match_most_recent_folder(most_recent_folder=SequenceDataFiles(dir=custom_path,
277
- child_dirs=[],
278
- sequence_name="NA")).ok_value)
351
+ self.fuzzy_match_most_recent_folder(
352
+ most_recent_folder=SequenceDataFiles(
353
+ dir=custom_path, child_dirs=[], sequence_name="NA"
354
+ )
355
+ ).ok_value
356
+ )
279
357
  parent_dir = self.data_files[-1]
280
358
  spectra = self.get_data()
281
359
  reports = []
282
360
  for i, child_dir in enumerate(parent_dir.child_dirs):
283
361
  metd_report = self.get_report_details(child_dir, report_type)
284
- child_spectra: List[AgilentHPLCChromatogram] = list(spectra[i].__dict__.values())
362
+ child_spectra: List[AgilentHPLCChromatogram] = list(
363
+ spectra[i].__dict__.values()
364
+ )
285
365
  for j, signal in enumerate(metd_report.signals):
286
366
  possible_data = child_spectra[j]
287
367
  if len(possible_data.x) > 0: