pychemstation 0.5.5__tar.gz → 0.5.6.dev1__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.
Files changed (40) hide show
  1. {pychemstation-0.5.5 → pychemstation-0.5.6.dev1}/PKG-INFO +1 -1
  2. {pychemstation-0.5.5 → pychemstation-0.5.6.dev1}/pychemstation/control/controllers/method.py +19 -9
  3. {pychemstation-0.5.5 → pychemstation-0.5.6.dev1}/pychemstation/control/controllers/sequence.py +18 -16
  4. {pychemstation-0.5.5 → pychemstation-0.5.6.dev1}/pychemstation/control/controllers/table_controller.py +32 -22
  5. {pychemstation-0.5.5 → pychemstation-0.5.6.dev1}/pychemstation/utils/chromatogram.py +1 -1
  6. {pychemstation-0.5.5 → pychemstation-0.5.6.dev1}/pychemstation.egg-info/PKG-INFO +1 -1
  7. {pychemstation-0.5.5 → pychemstation-0.5.6.dev1}/setup.py +1 -1
  8. {pychemstation-0.5.5 → pychemstation-0.5.6.dev1}/tests/test_comb.py +2 -2
  9. {pychemstation-0.5.5 → pychemstation-0.5.6.dev1}/LICENSE +0 -0
  10. {pychemstation-0.5.5 → pychemstation-0.5.6.dev1}/README.md +0 -0
  11. {pychemstation-0.5.5 → pychemstation-0.5.6.dev1}/pychemstation/__init__.py +0 -0
  12. {pychemstation-0.5.5 → pychemstation-0.5.6.dev1}/pychemstation/analysis/__init__.py +0 -0
  13. {pychemstation-0.5.5 → pychemstation-0.5.6.dev1}/pychemstation/analysis/base_spectrum.py +0 -0
  14. {pychemstation-0.5.5 → pychemstation-0.5.6.dev1}/pychemstation/analysis/spec_utils.py +0 -0
  15. {pychemstation-0.5.5 → pychemstation-0.5.6.dev1}/pychemstation/analysis/utils.py +0 -0
  16. {pychemstation-0.5.5 → pychemstation-0.5.6.dev1}/pychemstation/control/__init__.py +0 -0
  17. {pychemstation-0.5.5 → pychemstation-0.5.6.dev1}/pychemstation/control/controllers/__init__.py +0 -0
  18. {pychemstation-0.5.5 → pychemstation-0.5.6.dev1}/pychemstation/control/controllers/comm.py +0 -0
  19. {pychemstation-0.5.5 → pychemstation-0.5.6.dev1}/pychemstation/control/hplc.py +0 -0
  20. {pychemstation-0.5.5 → pychemstation-0.5.6.dev1}/pychemstation/generated/__init__.py +0 -0
  21. {pychemstation-0.5.5 → pychemstation-0.5.6.dev1}/pychemstation/generated/dad_method.py +0 -0
  22. {pychemstation-0.5.5 → pychemstation-0.5.6.dev1}/pychemstation/generated/pump_method.py +0 -0
  23. {pychemstation-0.5.5 → pychemstation-0.5.6.dev1}/pychemstation/utils/__init__.py +0 -0
  24. {pychemstation-0.5.5 → pychemstation-0.5.6.dev1}/pychemstation/utils/macro.py +0 -0
  25. {pychemstation-0.5.5 → pychemstation-0.5.6.dev1}/pychemstation/utils/method_types.py +0 -0
  26. {pychemstation-0.5.5 → pychemstation-0.5.6.dev1}/pychemstation/utils/parsing.py +0 -0
  27. {pychemstation-0.5.5 → pychemstation-0.5.6.dev1}/pychemstation/utils/sequence_types.py +0 -0
  28. {pychemstation-0.5.5 → pychemstation-0.5.6.dev1}/pychemstation/utils/table_types.py +0 -0
  29. {pychemstation-0.5.5 → pychemstation-0.5.6.dev1}/pychemstation/utils/tray_types.py +0 -0
  30. {pychemstation-0.5.5 → pychemstation-0.5.6.dev1}/pychemstation.egg-info/SOURCES.txt +0 -0
  31. {pychemstation-0.5.5 → pychemstation-0.5.6.dev1}/pychemstation.egg-info/dependency_links.txt +0 -0
  32. {pychemstation-0.5.5 → pychemstation-0.5.6.dev1}/pychemstation.egg-info/requires.txt +0 -0
  33. {pychemstation-0.5.5 → pychemstation-0.5.6.dev1}/pychemstation.egg-info/top_level.txt +0 -0
  34. {pychemstation-0.5.5 → pychemstation-0.5.6.dev1}/pyproject.toml +0 -0
  35. {pychemstation-0.5.5 → pychemstation-0.5.6.dev1}/setup.cfg +0 -0
  36. {pychemstation-0.5.5 → pychemstation-0.5.6.dev1}/tests/__init__.py +0 -0
  37. {pychemstation-0.5.5 → pychemstation-0.5.6.dev1}/tests/constants.py +0 -0
  38. {pychemstation-0.5.5 → pychemstation-0.5.6.dev1}/tests/test_comm.py +0 -0
  39. {pychemstation-0.5.5 → pychemstation-0.5.6.dev1}/tests/test_method.py +0 -0
  40. {pychemstation-0.5.5 → pychemstation-0.5.6.dev1}/tests/test_sequence.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pychemstation
3
- Version: 0.5.5
3
+ Version: 0.5.6.dev1
4
4
  Summary: Library to interact with Chemstation software, primarily used in Hein lab
5
5
  Home-page: https://gitlab.com/heingroup/device-api/pychemstation
6
6
  Author: Lucy Hao
@@ -51,9 +51,10 @@ class MethodController(TableController):
51
51
  rows = self.get_num_rows()
52
52
  if rows.is_ok():
53
53
  timetable_rows = [self.get_row(r + 1) for r in range(int(rows.ok_value.num_response))]
54
- return MethodTimetable(
54
+ self.table_state = MethodTimetable(
55
55
  first_row=self.get_method_params(),
56
56
  subsequent_rows=timetable_rows)
57
+ return self.table_state
57
58
  else:
58
59
  raise RuntimeError(rows.err_value)
59
60
 
@@ -88,6 +89,7 @@ class MethodController(TableController):
88
89
  if res.is_ok():
89
90
  parsed_response = res.ok_value.string_response
90
91
  assert parsed_response == f"{method_name}.M", "Switching Methods failed."
92
+ self.table_state = None
91
93
 
92
94
  def load_from_disk(self, method_name: str) -> MethodTimetable:
93
95
  """
@@ -118,7 +120,7 @@ class MethodController(TableController):
118
120
  elif solvent.channel == "Channel_B":
119
121
  organic_modifier = solvent
120
122
 
121
- return MethodTimetable(
123
+ self.table_state = MethodTimetable(
122
124
  first_row=HPLCMethodParams(
123
125
  organic_modifier=organic_modifier.percentage,
124
126
  flow=method.flow,
@@ -135,6 +137,7 @@ class MethodController(TableController):
135
137
  organic_modifier=organic_modifier,
136
138
  modifier_a=aq_modifier
137
139
  )
140
+ return self.table_state
138
141
  else:
139
142
  raise FileNotFoundError
140
143
 
@@ -242,7 +245,7 @@ class MethodController(TableController):
242
245
  """
243
246
  self.send(Command.STOP_METHOD_CMD)
244
247
 
245
- def run(self, experiment_name: str):
248
+ def run(self, experiment_name: str, stall_while_running: bool = True):
246
249
  """
247
250
  This is the preferred method to trigger a run.
248
251
  Starts the currently selected method, storing data
@@ -261,14 +264,21 @@ class MethodController(TableController):
261
264
  folder_name = f"{experiment_name}_{timestamp}.D"
262
265
  self.data_files.append(os.path.join(self.data_dir, folder_name))
263
266
 
264
- run_completed = self.check_hplc_done_running()
265
-
266
- if not run_completed.is_ok():
267
- raise RuntimeError("Run did not complete as expected")
267
+ if stall_while_running:
268
+ run_completed = self.check_hplc_done_running(method=self.table_state)
269
+ if run_completed.is_ok():
270
+ self.data_files[-1] = run_completed.value
271
+ else:
272
+ raise RuntimeError("Run error has occurred.")
273
+ else:
274
+ self.data_files[-1].dir = self.fuzzy_match_most_recent_folder(folder_name).ok_value
268
275
 
269
276
  def retrieve_recent_data_files(self) -> str:
270
277
  return self.data_files[-1]
271
278
 
272
- def get_data(self) -> AgilentChannelChromatogramData:
273
- self.get_spectrum(self.data_files[-1])
279
+ def get_data(self, custom_path: Optional[str] = None) -> AgilentChannelChromatogramData:
280
+ if not custom_path:
281
+ self.get_spectrum(self.data_files[-1])
282
+ else:
283
+ self.get_spectrum(custom_path)
274
284
  return AgilentChannelChromatogramData(**self.spectra)
@@ -1,3 +1,6 @@
1
+ from typing import Optional
2
+
3
+
1
4
  import os
2
5
  import time
3
6
 
@@ -24,9 +27,10 @@ class SequenceController(TableController):
24
27
  seq_name = self.receive()
25
28
 
26
29
  if rows.is_ok() and seq_name.is_ok():
27
- return SequenceTable(
30
+ self.table_state = SequenceTable(
28
31
  name=seq_name.ok_value.string_response.partition(".S")[0],
29
32
  rows=[self.get_row(r + 1) for r in range(int(rows.ok_value.num_response))])
33
+ return self.table_state
30
34
  raise RuntimeError(rows.err_value)
31
35
 
32
36
  def get_row(self, row: int) -> SequenceEntry:
@@ -60,6 +64,7 @@ class SequenceController(TableController):
60
64
  parsed_response = self.receive().value.string_response
61
65
 
62
66
  assert parsed_response == f"{seq_name}.S", "Switching sequence failed."
67
+ self.table_state = None
63
68
 
64
69
  def edit(self, sequence_table: SequenceTable):
65
70
  """
@@ -166,7 +171,7 @@ class SequenceController(TableController):
166
171
 
167
172
  self.send(Command.SAVE_SEQUENCE_CMD)
168
173
 
169
- def run(self):
174
+ def run(self, stall_while_running: bool = True):
170
175
  """
171
176
  Starts the currently loaded sequence, storing data
172
177
  under the <data_dir>/<sequence table name> folder.
@@ -181,19 +186,21 @@ class SequenceController(TableController):
181
186
  self.data_files.append(SequenceDataFiles(dir=folder_name,
182
187
  sequence_name=seq_table.name))
183
188
 
184
- run_completed = self.check_hplc_done_running(sequence=seq_table)
185
-
186
- if run_completed.is_ok():
187
- self.data_files[-1].dir = run_completed.value
188
- else:
189
- raise RuntimeError("Run error has occured.")
189
+ if stall_while_running:
190
+ run_completed = self.check_hplc_done_running(sequence=seq_table)
191
+ if run_completed.is_ok():
192
+ self.data_files[-1].dir = run_completed.value
193
+ else:
194
+ raise RuntimeError("Run error has occurred.")
195
+ else:
196
+ self.data_files[-1].dir = self.fuzzy_match_most_recent_folder(folder_name).ok_value
190
197
 
191
198
  def retrieve_recent_data_files(self):
192
199
  sequence_data_files: SequenceDataFiles = self.data_files[-1]
193
200
  return sequence_data_files.dir
194
201
 
195
- def get_data(self) -> list[AgilentChannelChromatogramData]:
196
- parent_dir = self.data_files[-1].dir
202
+ def get_data(self, custom_path:Optional[str] = None ) -> list[AgilentChannelChromatogramData]:
203
+ parent_dir = self.data_files[-1].dir if not custom_path else custom_path
197
204
  subdirs = [x[0] for x in os.walk(self.data_dir)]
198
205
  potential_folders = sorted(list(filter(lambda d: parent_dir in d, subdirs)))
199
206
  self.data_files[-1].child_dirs = [f for f in potential_folders if
@@ -202,10 +209,5 @@ class SequenceController(TableController):
202
209
  spectra: list[AgilentChannelChromatogramData] = []
203
210
  for row in self.data_files[-1].child_dirs:
204
211
  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"]))
212
+ spectra.append(AgilentChannelChromatogramData(**self.spectra))
211
213
  return spectra
@@ -6,7 +6,6 @@ Authors: Lucy Hao
6
6
 
7
7
  import abc
8
8
  import os
9
- import time
10
9
  from typing import Union, Optional
11
10
 
12
11
  import polling
@@ -25,6 +24,7 @@ class TableController(abc.ABC):
25
24
  def __init__(self, controller: CommunicationController, src: str, data_dir: str, table: Table):
26
25
  self.controller = controller
27
26
  self.table = table
27
+ self.table_state : Optional[TableController] = None
28
28
 
29
29
  if os.path.isdir(src):
30
30
  self.src: str = src
@@ -120,7 +120,7 @@ class TableController(abc.ABC):
120
120
  self.send(TableOperation.CREATE_TABLE.value.format(register=self.table.register,
121
121
  table_name=self.table.name))
122
122
 
123
- def get_num_rows(self) -> Result[int, str]:
123
+ def get_num_rows(self) -> Result[Response, str]:
124
124
  self.send(TableOperation.GET_NUM_ROWS.value.format(register=self.table.register,
125
125
  table_name=self.table.name,
126
126
  col_name=RegisterFlag.NUM_ROWS))
@@ -139,8 +139,8 @@ class TableController(abc.ABC):
139
139
  def check_hplc_is_running(self) -> bool:
140
140
  started_running = polling.poll(
141
141
  lambda: isinstance(self.controller.get_status(), HPLCRunningStatus),
142
- step=30,
143
- max_tries=10)
142
+ step=5,
143
+ max_tries=100)
144
144
  return started_running
145
145
 
146
146
  def check_hplc_done_running(self,
@@ -154,7 +154,7 @@ class TableController(abc.ABC):
154
154
  """
155
155
  timeout = 10 * 60
156
156
  if method:
157
- timeout = ((method.first_row.maximum_run_time + 2) * 60)
157
+ timeout = ((method.first_row.maximum_run_time + 5) * 60)
158
158
  if sequence:
159
159
  timeout *= len(sequence.rows)
160
160
 
@@ -162,26 +162,36 @@ class TableController(abc.ABC):
162
162
  finished_run = polling.poll(
163
163
  lambda: self.controller.check_if_running(),
164
164
  timeout=timeout,
165
- step=60
166
- )
167
-
168
- if finished_run:
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)
165
+ step=18)
166
+
167
+ check_folder = self.fuzzy_match_most_recent_folder(most_recent_folder)
168
+ if check_folder.is_ok() and finished_run:
169
+ return check_folder
170
+ elif check_folder.is_ok():
171
+ finished_run = polling.poll(
172
+ lambda: self.controller.check_if_running(),
173
+ timeout=timeout,
174
+ step=12)
175
+ if finished_run:
176
+ return check_folder
182
177
  else:
183
178
  return Err("Run did not complete as expected")
184
179
 
180
+ def fuzzy_match_most_recent_folder(self, most_recent_folder) -> Result[str, str]:
181
+ if os.path.exists(most_recent_folder):
182
+ return Ok(most_recent_folder)
183
+
184
+ subdirs = [x[0] for x in os.walk(self.data_dir)]
185
+ potential_folders = sorted(list(filter(lambda d: most_recent_folder in d, subdirs)))
186
+ parent_dirs = []
187
+ for folder in potential_folders:
188
+ path = os.path.normpath(folder)
189
+ split_folder = path.split(os.sep)
190
+ if most_recent_folder in split_folder[-1]:
191
+ parent_dirs.append(folder)
192
+ parent_dir = sorted(parent_dirs, reverse=True)[0]
193
+ return Ok(parent_dir)
194
+
185
195
  @abc.abstractmethod
186
196
  def retrieve_recent_data_files(self):
187
197
  pass
@@ -16,7 +16,7 @@ ACQUISITION_PARAMETERS = "acq.txt"
16
16
 
17
17
  # format used in acquisition parameters
18
18
  TIME_FORMAT = "%Y-%m-%d %H-%M-%S"
19
- SEQUENCE_TIME_FORMAT = "%Y-%m-%d %H"
19
+ SEQUENCE_TIME_FORMAT = "%Y-%m-%d %H-%M"
20
20
 
21
21
 
22
22
  class AgilentHPLCChromatogram(AbstractSpectrum):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pychemstation
3
- Version: 0.5.5
3
+ Version: 0.5.6.dev1
4
4
  Summary: Library to interact with Chemstation software, primarily used in Hein lab
5
5
  Home-page: https://gitlab.com/heingroup/device-api/pychemstation
6
6
  Author: Lucy Hao
@@ -5,7 +5,7 @@ with open("README.md", "r") as fh:
5
5
 
6
6
  setuptools.setup(
7
7
  name="pychemstation",
8
- version="0.5.5",
8
+ version="0.5.6.dev1",
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",
@@ -28,14 +28,14 @@ class TestCombinations(unittest.TestCase):
28
28
  first_row=HPLCMethodParams(
29
29
  organic_modifier=5,
30
30
  flow=0.65,
31
- maximum_run_time=2),
31
+ maximum_run_time=1),
32
32
  subsequent_rows=[
33
33
  TimeTableEntry(
34
34
  start_time=0.10,
35
35
  organic_modifer=5,
36
36
  flow=0.34),
37
37
  TimeTableEntry(
38
- start_time=1,
38
+ start_time=0.5,
39
39
  organic_modifer=98,
40
40
  flow=0.55)])
41
41
  self.hplc_controller.edit_method(rand_method, save=True)