pychemstation 0.5.5__py3-none-any.whl → 0.5.6.dev1__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.
@@ -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
@@ -12,8 +12,8 @@ from typing import Union, Optional
12
12
  import polling
13
13
  from result import Result, Ok, Err
14
14
 
15
- from ...control import CommunicationController
16
- from ...utils.chromatogram import AgilentHPLCChromatogram
15
+ from ...control.controllers.comm import CommunicationController
16
+ from ...utils.chromatogram import AgilentHPLCChromatogram, AgilentChannelChromatogramData
17
17
  from ...utils.macro import Command, HPLCRunningStatus, Response
18
18
  from ...utils.method_types import MethodTimetable
19
19
  from ...utils.sequence_types import SequenceDataFiles, SequenceTable
@@ -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,
@@ -162,32 +162,35 @@ 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
165
+ step=12
166
166
  )
167
167
 
168
168
  if finished_run:
169
169
  if os.path.exists(most_recent_folder):
170
170
  return Ok(most_recent_folder)
171
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)
172
+ return self.fuzzy_match_most_recent_folder(most_recent_folder)
182
173
  else:
183
174
  return Err("Run did not complete as expected")
184
175
 
176
+ def fuzzy_match_most_recent_folder(self, most_recent_folder) -> Result[str, str]:
177
+ subdirs = [x[0] for x in os.walk(self.data_dir)]
178
+ potential_folders = sorted(list(filter(lambda d: most_recent_folder in d, subdirs)))
179
+ parent_dirs = []
180
+ for folder in potential_folders:
181
+ path = os.path.normpath(folder)
182
+ split_folder = path.split(os.sep)
183
+ if most_recent_folder in split_folder[-1]:
184
+ parent_dirs.append(folder)
185
+ parent_dir = sorted(parent_dirs, reverse=True)[0]
186
+ return Ok(parent_dir)
187
+
185
188
  @abc.abstractmethod
186
189
  def retrieve_recent_data_files(self):
187
190
  pass
188
191
 
189
192
  @abc.abstractmethod
190
- def get_data(self) -> tuple[bool,]:
193
+ def get_data(self) -> Union[list[AgilentChannelChromatogramData], AgilentChannelChromatogramData]:
191
194
  pass
192
195
 
193
196
  def get_spectrum(self, data_file: str):
@@ -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
@@ -8,18 +8,18 @@ pychemstation/control/comm.py,sha256=u44g1hTluQ0yUG93Un-QAshScoDpgYRrZfFTgweP5tY
8
8
  pychemstation/control/hplc.py,sha256=L1-cBQ7-thuITx1Mqq3lYXo832nEQtRJEX7nlLvRYrg,6732
9
9
  pychemstation/control/controllers/__init__.py,sha256=di3ytLIK-35XC_THw4IjNaOtCUTe7GuEOFb-obmREw4,166
10
10
  pychemstation/control/controllers/comm.py,sha256=iltKMNfdp_8INA5Vss9asI2LxJam_Ro3YWBHBQFr4t0,7353
11
- pychemstation/control/controllers/method.py,sha256=SoKwteVfalgP1z7aKPNlaUJ01Gsr0MIoa7f-c2sjDrE,12259
12
- pychemstation/control/controllers/sequence.py,sha256=bHx15uSA0ZjAy6xpyxwhWUNP54WcEL0nJ24bzYCa4rc,10719
13
- pychemstation/control/controllers/table_controller.py,sha256=N47eiowmmy9gi18fChNh-cW6z8bbRSF30pLzhnWG9_k,8227
11
+ pychemstation/control/controllers/method.py,sha256=GNGvGUF9LUCcHAe37SIdnQQ_RzwgnU2ba1oWLXnOp8w,12816
12
+ pychemstation/control/controllers/sequence.py,sha256=f4ZhzkM2hY8xk8dUyiCpmZ5fwU4ev2-CNSbyFeFVe_w,10963
13
+ pychemstation/control/controllers/table_controller.py,sha256=DnusCG5ySR8gA-oe3K_EJfAPlYhmW33epiCi4YVUKJg,8648
14
14
  pychemstation/control/table/__init__.py,sha256=RgMN4uIWHdNUHpGRBWdzmzAbk7XEKl6Y-qtqWCxzSZU,124
15
15
  pychemstation/control/table/method.py,sha256=THVoGomSXff_CTU3eAYme0BYwkPzab5UgZKsiZ29QSk,12196
16
16
  pychemstation/control/table/sequence.py,sha256=Eri52AnbE3BGthfrRSvYKYciquUzvHKo0lYUTySYYE8,10542
17
- pychemstation/control/table/table_controller.py,sha256=F5lv1DlPkEDcFmtwVT-E9Kq075jnWIN-iZIM3_mTt5E,8115
17
+ pychemstation/control/table/table_controller.py,sha256=HVNYUXqtyFTAvb67fa3RO5RHgmBTFMsYRHKpiXdYcfs,8313
18
18
  pychemstation/generated/__init__.py,sha256=GAoZFAYbPVEJDkcOw3e1rgOqd7TCW0HyKNPM8OMehMg,1005
19
19
  pychemstation/generated/dad_method.py,sha256=0W8Z5WDtF5jpIcudMqb7XrkTnR2EGg_QOCsHRFQ0rmM,8402
20
20
  pychemstation/generated/pump_method.py,sha256=sUhE2Oo00nzVcoONtq3EMWsN4wLSryXbG8f3EeViWKg,12174
21
21
  pychemstation/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
- pychemstation/utils/chromatogram.py,sha256=KzhEQbxKbwOu4OjKa4XJFq2y08JUwMRoaupHrDR8cLM,3094
22
+ pychemstation/utils/chromatogram.py,sha256=RiKWQG2FIlDzddhgABV-WIJg_BsCTL_wPfyYGikyxoM,3097
23
23
  pychemstation/utils/macro.py,sha256=BAIcE_dppNffwrSqGq8gh0ccE9YAJfQFQZHXJgA1WtA,2586
24
24
  pychemstation/utils/method_types.py,sha256=YngbyHg96JSFnvhm5Zd7wJvLTQPPQsLbvbyz3HlGLYY,862
25
25
  pychemstation/utils/parsing.py,sha256=bnFIsZZwFy9NKzVUf517yN-ogzQbm0hp_aho3KUD6Is,9317
@@ -28,12 +28,12 @@ pychemstation/utils/table_types.py,sha256=cN51Ry2pammDdk85cabVH3qkchjKKIzZfAH87P
28
28
  pychemstation/utils/tray_types.py,sha256=UUDED-IAf-8FmPVZezuWSiIQE_HgiZQMV2sTqu4oZw8,177
29
29
  tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
30
  tests/constants.py,sha256=lLwT_QaVriivL5llkul6RxXxPriwUp1E-Y3G9fejvbo,2092
31
- tests/test_comb.py,sha256=faF4764oJEZ2vhG9-zLmQxjATseipRKXrStehuDCXOI,5638
31
+ tests/test_comb.py,sha256=CF6nSxUMBJeUjA-IfgPcBGV5oIG4aH1-RA26oIATa-s,5640
32
32
  tests/test_comm.py,sha256=1ZZd0UrIBOKe91wzA-XI-gSRgXmId9mLWYSMeche82Y,2973
33
33
  tests/test_method.py,sha256=uCPpZVYKPz1CNWwhmBo_8TH0ku2V0ZpDZJj3f8iINB4,2440
34
34
  tests/test_sequence.py,sha256=yIQGhUTehtHz6D1ai5W6AlP0zes2icF0VdQ0IGJ2CbQ,4901
35
- pychemstation-0.5.5.dist-info/LICENSE,sha256=9bdF75gIf1MecZ7oymqWgJREVz7McXPG-mjqrTmzzD8,18658
36
- pychemstation-0.5.5.dist-info/METADATA,sha256=sAsryhHjIHyT6y10BQP2rEUh49dLJ_2wCchNgQ1M4JY,4307
37
- pychemstation-0.5.5.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
38
- pychemstation-0.5.5.dist-info/top_level.txt,sha256=zXfKu_4nYWwPHo3OsuhshMNC3SPkcoTGCyODjURaghY,20
39
- pychemstation-0.5.5.dist-info/RECORD,,
35
+ pychemstation-0.5.6.dev1.dist-info/LICENSE,sha256=9bdF75gIf1MecZ7oymqWgJREVz7McXPG-mjqrTmzzD8,18658
36
+ pychemstation-0.5.6.dev1.dist-info/METADATA,sha256=7Pj5MObTqRmX3B19nhA70BzBRyHSA7bDku7O1-D89lE,4312
37
+ pychemstation-0.5.6.dev1.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
38
+ pychemstation-0.5.6.dev1.dist-info/top_level.txt,sha256=zXfKu_4nYWwPHo3OsuhshMNC3SPkcoTGCyODjURaghY,20
39
+ pychemstation-0.5.6.dev1.dist-info/RECORD,,
tests/test_comb.py CHANGED
@@ -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)