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
@@ -3,6 +3,7 @@ Abstract module containing shared logic for Method and Sequence tables.
3
3
 
4
4
  Authors: Lucy Hao
5
5
  """
6
+
6
7
  from __future__ import annotations
7
8
 
8
9
  import abc
@@ -23,25 +24,27 @@ from ....analysis.process_report import (
23
24
  TXTProcessor,
24
25
  )
25
26
  from ....control.controllers.comm import CommunicationController
26
- from ....utils.chromatogram import (
27
+ from pychemstation.analysis.chromatogram import (
27
28
  AgilentChannelChromatogramData,
28
29
  AgilentHPLCChromatogram,
29
30
  )
30
31
  from ....utils.macro import Command, HPLCRunningStatus, Response
31
32
  from ....utils.method_types import MethodDetails
32
- from ....utils.sequence_types import SequenceDataFiles, SequenceTable
33
+ from ....utils.sequence_types import SequenceTable
33
34
  from ....utils.table_types import RegisterFlag, T, Table, TableOperation
34
35
 
35
36
  TableType = Union[MethodDetails, SequenceTable]
36
37
 
37
38
 
38
39
  class TableController(abc.ABC):
39
-
40
- def __init__(self, controller: CommunicationController,
41
- src: Optional[str],
42
- data_dirs: Optional[List[str]],
43
- table: Table,
44
- offline: bool = False):
40
+ def __init__(
41
+ self,
42
+ controller: CommunicationController,
43
+ src: Optional[str],
44
+ data_dirs: Optional[List[str]],
45
+ table: Table,
46
+ offline: bool = False,
47
+ ):
45
48
  self.controller = controller
46
49
  self.table_locator = table
47
50
  self.table_state: Optional[TableType] = None
@@ -71,7 +74,7 @@ class TableController(abc.ABC):
71
74
  "H": AgilentHPLCChromatogram(),
72
75
  }
73
76
  self.report: Optional[AgilentReport] = None
74
- self.uv: Dict[str, AgilentHPLCChromatogram] = {}
77
+ self.uv: Dict[int, AgilentHPLCChromatogram] = {}
75
78
  self.data_files: List = []
76
79
 
77
80
  def receive(self) -> Result[Response, str]:
@@ -85,7 +88,8 @@ class TableController(abc.ABC):
85
88
  def send(self, cmd: Union[Command, str]):
86
89
  if not self.controller:
87
90
  raise RuntimeError(
88
- "Communication controller must be initialized before sending command. It is currently in offline mode.")
91
+ "Communication controller must be initialized before sending command. It is currently in offline mode."
92
+ )
89
93
  self.controller.send(cmd)
90
94
 
91
95
  def sleepy_send(self, cmd: Union[Command, str]):
@@ -100,108 +104,145 @@ class TableController(abc.ABC):
100
104
  self.send(Command.SLEEP_CMD.value.format(seconds=seconds))
101
105
 
102
106
  def get_num(self, row: int, col_name: RegisterFlag) -> Union[int, float]:
103
- return self.controller.get_num_val(TableOperation.GET_ROW_VAL.value.format(register=self.table_locator.register,
104
- table_name=self.table_locator.name,
105
- row=row,
106
- col_name=col_name.value))
107
+ return self.controller.get_num_val(
108
+ TableOperation.GET_ROW_VAL.value.format(
109
+ register=self.table_locator.register,
110
+ table_name=self.table_locator.name,
111
+ row=row,
112
+ col_name=col_name.value,
113
+ )
114
+ )
107
115
 
108
116
  def get_text(self, row: int, col_name: RegisterFlag) -> str:
109
117
  return self.controller.get_text_val(
110
- TableOperation.GET_ROW_TEXT.value.format(register=self.table_locator.register,
111
- table_name=self.table_locator.name,
112
- row=row,
113
- col_name=col_name.value))
114
-
115
- def add_new_col_num(self,
116
- col_name: RegisterFlag,
117
- val: Union[int, float]):
118
- self.sleepy_send(TableOperation.NEW_COL_VAL.value.format(
119
- register=self.table_locator.register,
120
- table_name=self.table_locator.name,
121
- col_name=col_name,
122
- val=val))
123
-
124
- def add_new_col_text(self,
125
- col_name: RegisterFlag,
126
- val: str):
127
- self.sleepy_send(TableOperation.NEW_COL_TEXT.value.format(
128
- register=self.table_locator.register,
129
- table_name=self.table_locator.name,
130
- col_name=col_name,
131
- val=val))
132
-
133
- def _edit_row_num(self,
134
- col_name: RegisterFlag,
135
- val: Union[int, float],
136
- row: Optional[int] = None):
137
- self.sleepy_send(TableOperation.EDIT_ROW_VAL.value.format(
138
- register=self.table_locator.register,
139
- table_name=self.table_locator.name,
140
- row=row if row is not None else 'Rows',
141
- col_name=col_name,
142
- val=val))
143
-
144
- def _edit_row_text(self,
145
- col_name: RegisterFlag,
146
- val: str,
147
- row: Optional[int] = None):
148
- self.sleepy_send(TableOperation.EDIT_ROW_TEXT.value.format(
149
- register=self.table_locator.register,
150
- table_name=self.table_locator.name,
151
- row=row if row is not None else 'Rows',
152
- col_name=col_name,
153
- val=val))
118
+ TableOperation.GET_ROW_TEXT.value.format(
119
+ register=self.table_locator.register,
120
+ table_name=self.table_locator.name,
121
+ row=row,
122
+ col_name=col_name.value,
123
+ )
124
+ )
125
+
126
+ def add_new_col_num(self, col_name: RegisterFlag, val: Union[int, float]):
127
+ self.sleepy_send(
128
+ TableOperation.NEW_COL_VAL.value.format(
129
+ register=self.table_locator.register,
130
+ table_name=self.table_locator.name,
131
+ col_name=col_name,
132
+ val=val,
133
+ )
134
+ )
135
+
136
+ def add_new_col_text(self, col_name: RegisterFlag, val: str):
137
+ self.sleepy_send(
138
+ TableOperation.NEW_COL_TEXT.value.format(
139
+ register=self.table_locator.register,
140
+ table_name=self.table_locator.name,
141
+ col_name=col_name,
142
+ val=val,
143
+ )
144
+ )
145
+
146
+ def _edit_row_num(
147
+ self, col_name: RegisterFlag, val: Union[int, float], row: Optional[int] = None
148
+ ):
149
+ self.sleepy_send(
150
+ TableOperation.EDIT_ROW_VAL.value.format(
151
+ register=self.table_locator.register,
152
+ table_name=self.table_locator.name,
153
+ row=row if row is not None else "Rows",
154
+ col_name=col_name,
155
+ val=val,
156
+ )
157
+ )
158
+
159
+ def _edit_row_text(
160
+ self, col_name: RegisterFlag, val: str, row: Optional[int] = None
161
+ ):
162
+ self.sleepy_send(
163
+ TableOperation.EDIT_ROW_TEXT.value.format(
164
+ register=self.table_locator.register,
165
+ table_name=self.table_locator.name,
166
+ row=row if row is not None else "Rows",
167
+ col_name=col_name,
168
+ val=val,
169
+ )
170
+ )
154
171
 
155
172
  @abc.abstractmethod
156
173
  def get_row(self, row: int):
157
174
  pass
158
175
 
159
176
  def delete_row(self, row: int):
160
- self.sleepy_send(TableOperation.DELETE_ROW.value.format(register=self.table_locator.register,
161
- table_name=self.table_locator.name,
162
- row=row))
177
+ self.sleepy_send(
178
+ TableOperation.DELETE_ROW.value.format(
179
+ register=self.table_locator.register,
180
+ table_name=self.table_locator.name,
181
+ row=row,
182
+ )
183
+ )
163
184
 
164
185
  def add_row(self):
165
186
  """
166
187
  Adds a row to the provided table for currently loaded method or sequence.
167
188
  """
168
- self.sleepy_send(TableOperation.NEW_ROW.value.format(register=self.table_locator.register,
169
- table_name=self.table_locator.name))
189
+ self.sleepy_send(
190
+ TableOperation.NEW_ROW.value.format(
191
+ register=self.table_locator.register, table_name=self.table_locator.name
192
+ )
193
+ )
170
194
 
171
195
  def delete_table(self):
172
196
  """
173
197
  Deletes the table for the current loaded method or sequence.
174
198
  """
175
- self.sleepy_send(TableOperation.DELETE_TABLE.value.format(register=self.table_locator.register,
176
- table_name=self.table_locator.name))
199
+ self.sleepy_send(
200
+ TableOperation.DELETE_TABLE.value.format(
201
+ register=self.table_locator.register, table_name=self.table_locator.name
202
+ )
203
+ )
177
204
 
178
205
  def new_table(self):
179
206
  """
180
207
  Creates the table for the currently loaded method or sequence.
181
208
  """
182
- self.send(TableOperation.CREATE_TABLE.value.format(register=self.table_locator.register,
183
- table_name=self.table_locator.name))
209
+ self.send(
210
+ TableOperation.CREATE_TABLE.value.format(
211
+ register=self.table_locator.register, table_name=self.table_locator.name
212
+ )
213
+ )
184
214
 
185
215
  def get_num_rows(self) -> Result[Response, str]:
186
- self.send(TableOperation.GET_NUM_ROWS.value.format(register=self.table_locator.register,
187
- table_name=self.table_locator.name,
188
- col_name=RegisterFlag.NUM_ROWS))
189
- self.send(Command.GET_ROWS_CMD.value.format(register=self.table_locator.register,
190
- table_name=self.table_locator.name,
191
- col_name=RegisterFlag.NUM_ROWS))
216
+ self.send(
217
+ TableOperation.GET_NUM_ROWS.value.format(
218
+ register=self.table_locator.register,
219
+ table_name=self.table_locator.name,
220
+ col_name=RegisterFlag.NUM_ROWS,
221
+ )
222
+ )
223
+ self.send(
224
+ Command.GET_ROWS_CMD.value.format(
225
+ register=self.table_locator.register,
226
+ table_name=self.table_locator.name,
227
+ col_name=RegisterFlag.NUM_ROWS,
228
+ )
229
+ )
192
230
  res = self.controller.receive()
193
231
 
194
232
  if res.is_ok():
195
233
  self.send("Sleep 0.1")
196
- self.send('Print Rows')
234
+ self.send("Print Rows")
197
235
  return res
198
236
  else:
199
237
  return Err("No rows could be read.")
200
238
 
201
239
  def check_hplc_is_running(self) -> bool:
202
240
  try:
203
- started_running = polling.poll(lambda: isinstance(self.controller.get_status(), HPLCRunningStatus),
204
- step=1, max_tries=20)
241
+ started_running = polling.poll(
242
+ lambda: isinstance(self.controller.get_status(), HPLCRunningStatus),
243
+ step=1,
244
+ max_tries=20,
245
+ )
205
246
  except Exception as e:
206
247
  print(e)
207
248
  return False
@@ -212,7 +253,7 @@ class TableController(abc.ABC):
212
253
  def check_hplc_run_finished(self) -> Tuple[float, bool]:
213
254
  done_running = self.controller.check_if_not_running()
214
255
  if self.curr_run_starting_time and self.timeout:
215
- time_passed = (time.time() - self.curr_run_starting_time)
256
+ time_passed = time.time() - self.curr_run_starting_time
216
257
  if time_passed > self.timeout:
217
258
  enough_time_passed = time_passed >= self.timeout
218
259
  run_finished = enough_time_passed and done_running
@@ -235,13 +276,25 @@ class TableController(abc.ABC):
235
276
  try:
236
277
  finished_run = not polling.poll(
237
278
  lambda: self.check_hplc_run_finished()[1],
238
- max_tries=minutes - 1, step=50)
239
- except (polling.TimeoutException, polling.PollingException, polling.MaxCallException):
279
+ max_tries=minutes - 1,
280
+ step=50,
281
+ )
282
+ except (
283
+ polling.TimeoutException,
284
+ polling.PollingException,
285
+ polling.MaxCallException,
286
+ ):
240
287
  try:
241
288
  finished_run = polling.poll(
242
289
  lambda: self.check_hplc_run_finished()[1],
243
- timeout=self.timeout / 2, step=1)
244
- except (polling.TimeoutException, polling.PollingException, polling.MaxCallException):
290
+ timeout=self.timeout / 2,
291
+ step=1,
292
+ )
293
+ except (
294
+ polling.TimeoutException,
295
+ polling.PollingException,
296
+ polling.MaxCallException,
297
+ ):
245
298
  pass
246
299
 
247
300
  check_folder = self.fuzzy_match_most_recent_folder(self.data_files[-1])
@@ -250,14 +303,13 @@ class TableController(abc.ABC):
250
303
  elif check_folder.is_ok():
251
304
  try:
252
305
  finished_run = polling.poll(
253
- lambda: self.check_hplc_run_finished()[1],
254
- max_tries=10,
255
- step=50)
306
+ lambda: self.check_hplc_run_finished()[1], max_tries=10, step=50
307
+ )
256
308
  if finished_run:
257
309
  return check_folder
258
310
  except Exception:
259
311
  self._reset_time()
260
- return check_folder
312
+ return self.data_files[-1]
261
313
  return Err("Run did not complete as expected")
262
314
 
263
315
  @abc.abstractmethod
@@ -265,15 +317,23 @@ class TableController(abc.ABC):
265
317
  pass
266
318
 
267
319
  @abc.abstractmethod
268
- def get_data(self, custom_path: Optional[str] = None) -> Union[List[AgilentChannelChromatogramData], AgilentChannelChromatogramData]:
320
+ def get_data(
321
+ self, custom_path: Optional[str] = None
322
+ ) -> Union[List[AgilentChannelChromatogramData], AgilentChannelChromatogramData]:
269
323
  pass
270
324
 
271
325
  @abc.abstractmethod
272
- def get_data_uv(self) -> Union[List[Dict[str, AgilentHPLCChromatogram]], Dict[str, AgilentHPLCChromatogram]]:
326
+ def get_data_uv(
327
+ self,
328
+ ) -> Union[
329
+ List[Dict[str, AgilentHPLCChromatogram]], Dict[str, AgilentHPLCChromatogram]
330
+ ]:
273
331
  pass
274
332
 
275
333
  @abc.abstractmethod
276
- def get_report(self, report_type: ReportType = ReportType.TXT) -> List[AgilentReport]:
334
+ def get_report(
335
+ self, report_type: ReportType = ReportType.TXT
336
+ ) -> List[AgilentReport]:
277
337
  pass
278
338
 
279
339
  def get_uv_spectrum(self, path: str):
@@ -281,12 +341,13 @@ class TableController(abc.ABC):
281
341
  times = data_uv.xlabels
282
342
  wavelengths = data_uv.ylabels
283
343
  absorbances = data_uv.data.transpose()
284
- for (i, w) in enumerate(wavelengths):
344
+ for i, w in enumerate(wavelengths):
285
345
  self.uv[w] = AgilentHPLCChromatogram()
286
346
  self.uv[w].attach_spectrum(times, absorbances[i])
287
347
 
288
- def get_report_details(self, path: str,
289
- report_type: ReportType = ReportType.TXT) -> AgilentReport:
348
+ def get_report_details(
349
+ self, path: str, report_type: ReportType = ReportType.TXT
350
+ ) -> AgilentReport:
290
351
  if report_type is ReportType.TXT:
291
352
  txt_report = TXTProcessor(path).process_report()
292
353
  if txt_report.is_ok():
@@ -297,7 +358,6 @@ class TableController(abc.ABC):
297
358
  self.report = csv_report.ok_value
298
359
  return self.report
299
360
 
300
-
301
361
  def get_spectrum_at_channels(self, data_path: str):
302
362
  """
303
363
  Load chromatogram for any channel in spectra dictionary.