pychemstation 0.10.8.dev1__py3-none-any.whl → 0.10.8.dev3__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/control/controllers/data_aq/method.py +217 -57
- pychemstation/control/controllers/data_aq/sequence.py +103 -20
- pychemstation/control/hplc.py +30 -2
- pychemstation/utils/abc_tables/abc_comm.py +0 -1
- pychemstation/utils/abc_tables/run.py +11 -6
- pychemstation/utils/abc_tables/table.py +18 -13
- pychemstation/utils/macro.py +5 -2
- pychemstation/utils/method_types.py +1 -1
- pychemstation/utils/mocking/mock_comm.py +25 -2
- pychemstation/utils/mocking/mock_hplc.py +29 -1
- pychemstation/utils/table_types.py +2 -0
- {pychemstation-0.10.8.dev1.dist-info → pychemstation-0.10.8.dev3.dist-info}/METADATA +1 -1
- {pychemstation-0.10.8.dev1.dist-info → pychemstation-0.10.8.dev3.dist-info}/RECORD +15 -15
- {pychemstation-0.10.8.dev1.dist-info → pychemstation-0.10.8.dev3.dist-info}/WHEEL +0 -0
- {pychemstation-0.10.8.dev1.dist-info → pychemstation-0.10.8.dev3.dist-info}/licenses/LICENSE +0 -0
@@ -3,17 +3,18 @@ from __future__ import annotations
|
|
3
3
|
import os
|
4
4
|
import time
|
5
5
|
import warnings
|
6
|
-
from typing import List, Optional,
|
6
|
+
from typing import Dict, List, Optional, Set, Union, Tuple
|
7
7
|
|
8
8
|
from result import Err, Ok, Result
|
9
9
|
|
10
|
-
from ....analysis.process_report import AgilentReport, ReportType
|
11
|
-
from ....control.controllers import CommunicationController
|
12
10
|
from pychemstation.analysis.chromatogram import (
|
13
11
|
TIME_FORMAT,
|
14
12
|
AgilentChannelChromatogramData,
|
15
13
|
AgilentHPLCChromatogram,
|
16
14
|
)
|
15
|
+
|
16
|
+
from ....analysis.process_report import AgilentReport, ReportType
|
17
|
+
from ....control.controllers import CommunicationController
|
17
18
|
from ....utils.abc_tables.run import RunController
|
18
19
|
from ....utils.macro import Command
|
19
20
|
from ....utils.method_types import (
|
@@ -23,7 +24,7 @@ from ....utils.method_types import (
|
|
23
24
|
PType,
|
24
25
|
TimeTableEntry,
|
25
26
|
)
|
26
|
-
from ....utils.table_types import RegisterFlag, Table, TableOperation
|
27
|
+
from ....utils.table_types import RegisterFlag, T, Table, TableOperation
|
27
28
|
from ..devices.injector import InjectorController
|
28
29
|
|
29
30
|
|
@@ -77,26 +78,22 @@ class MethodController(RunController):
|
|
77
78
|
raise ValueError("Communication controller is offline!")
|
78
79
|
|
79
80
|
def get_row(self, row: int) -> TimeTableEntry:
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
start_time=self.get_num(row, RegisterFlag.TIME),
|
97
|
-
organic_modifer=om,
|
98
|
-
flow=flow,
|
99
|
-
)
|
81
|
+
function = self.get_text(row, RegisterFlag.FUNCTION)
|
82
|
+
if function == RegisterFlag.FLOW.value:
|
83
|
+
return TimeTableEntry(
|
84
|
+
start_time=self.get_num(row, RegisterFlag.TIME),
|
85
|
+
organic_modifer=None,
|
86
|
+
flow=self.get_num(row, RegisterFlag.TIMETABLE_FLOW),
|
87
|
+
)
|
88
|
+
if function == RegisterFlag.SOLVENT_COMPOSITION.value:
|
89
|
+
return TimeTableEntry(
|
90
|
+
start_time=self.get_num(row, RegisterFlag.TIME),
|
91
|
+
organic_modifer=self.get_num(
|
92
|
+
row, RegisterFlag.TIMETABLE_SOLVENT_B_COMPOSITION
|
93
|
+
),
|
94
|
+
flow=None,
|
95
|
+
)
|
96
|
+
raise ValueError("Both flow and organic modifier are empty")
|
100
97
|
|
101
98
|
def get_timetable(self, rows: int):
|
102
99
|
uncoalesced_timetable_rows = [self.get_row(r + 1) for r in range(rows)]
|
@@ -219,6 +216,7 @@ class MethodController(RunController):
|
|
219
216
|
new_stop_time=updated_method.stop_time,
|
220
217
|
new_post_time=updated_method.post_time,
|
221
218
|
)
|
219
|
+
self.validate_timetable(updated_method.timetable)
|
222
220
|
self.edit_method_timetable(updated_method.timetable)
|
223
221
|
|
224
222
|
if save:
|
@@ -229,6 +227,7 @@ class MethodController(RunController):
|
|
229
227
|
)
|
230
228
|
|
231
229
|
def edit_initial_om(self, new_om: Union[int, float]):
|
230
|
+
self._validate_organic_modifier(new_om)
|
232
231
|
initial_organic_modifier: Param = Param(
|
233
232
|
val=new_om,
|
234
233
|
chemstation_key=RegisterFlag.SOLVENT_B_COMPOSITION,
|
@@ -236,13 +235,31 @@ class MethodController(RunController):
|
|
236
235
|
)
|
237
236
|
self._update_param(initial_organic_modifier)
|
238
237
|
|
238
|
+
def _validate_organic_modifier(self, new_om):
|
239
|
+
if not (isinstance(new_om, int) or isinstance(new_om, float)):
|
240
|
+
raise ValueError("Organic modifier must be int or float")
|
241
|
+
if new_om < 0:
|
242
|
+
raise ValueError("Organic modifier must be positive")
|
243
|
+
if new_om > 100:
|
244
|
+
raise ValueError("Organic modifer must be less than 100.")
|
245
|
+
|
239
246
|
def edit_flow(self, new_flow: Union[int, float]):
|
247
|
+
self._validate_flow(new_flow)
|
240
248
|
flow: Param = Param(
|
241
249
|
val=new_flow, chemstation_key=RegisterFlag.FLOW, ptype=PType.NUM
|
242
250
|
)
|
243
251
|
self._update_param(flow)
|
244
252
|
|
253
|
+
def _validate_flow(self, new_flow):
|
254
|
+
if not (isinstance(new_flow, int) or isinstance(new_flow, float)):
|
255
|
+
raise ValueError("Flow must be int or float")
|
256
|
+
if new_flow < 0:
|
257
|
+
raise ValueError("Flow must be positive")
|
258
|
+
if new_flow >= 5.0:
|
259
|
+
raise ValueError("Flow must be less than 5.0")
|
260
|
+
|
245
261
|
def edit_stop_time(self, new_stop_time: Union[int, float]):
|
262
|
+
self.validate_stop_time(new_stop_time)
|
246
263
|
stop_time: Param = Param(
|
247
264
|
val=new_stop_time,
|
248
265
|
chemstation_key=RegisterFlag.MAX_TIME,
|
@@ -255,7 +272,14 @@ class MethodController(RunController):
|
|
255
272
|
)
|
256
273
|
self._update_param(stop_time)
|
257
274
|
|
275
|
+
def validate_stop_time(self, new_stop_time):
|
276
|
+
if not (isinstance(new_stop_time, int) or isinstance(new_stop_time, float)):
|
277
|
+
raise ValueError("Stop time must be int or float")
|
278
|
+
if new_stop_time < 0:
|
279
|
+
raise ValueError("Stop time must be positive")
|
280
|
+
|
258
281
|
def edit_post_time(self, new_post_time: Union[int, float]):
|
282
|
+
self.validate_post_time(new_post_time)
|
259
283
|
post_time: Param = Param(
|
260
284
|
val=new_post_time,
|
261
285
|
chemstation_key=RegisterFlag.POST_TIME,
|
@@ -266,6 +290,12 @@ class MethodController(RunController):
|
|
266
290
|
)
|
267
291
|
self._update_param(post_time)
|
268
292
|
|
293
|
+
def validate_post_time(self, new_post_time):
|
294
|
+
if not (isinstance(new_post_time, int) or isinstance(new_post_time, float)):
|
295
|
+
raise ValueError("Post time must be int or float")
|
296
|
+
if new_post_time < 0:
|
297
|
+
raise ValueError("Post time must be positive")
|
298
|
+
|
269
299
|
def update_method_params(
|
270
300
|
self,
|
271
301
|
new_flow: Union[int, float],
|
@@ -334,51 +364,146 @@ class MethodController(RunController):
|
|
334
364
|
self.sleepy_send("DownloadRCMethod PMP1")
|
335
365
|
self.send("Sleep 1")
|
336
366
|
|
337
|
-
def _edit_row(
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
367
|
+
def _edit_row(
|
368
|
+
self,
|
369
|
+
row: TimeTableEntry,
|
370
|
+
first_row: bool,
|
371
|
+
time_added: bool,
|
372
|
+
flow_added: bool,
|
373
|
+
om_added: bool,
|
374
|
+
function_added: bool,
|
375
|
+
) -> Tuple[bool, bool, bool, bool]:
|
376
|
+
def add_time():
|
377
|
+
nonlocal time_added
|
378
|
+
nonlocal first_row
|
379
|
+
if not time_added:
|
345
380
|
self.add_new_col_num(col_name=RegisterFlag.TIME, val=row.start_time)
|
381
|
+
time_added = True
|
382
|
+
elif not first_row:
|
383
|
+
self._edit_row_num(col_name=RegisterFlag.TIME, val=row.start_time)
|
384
|
+
|
385
|
+
def add_flow():
|
386
|
+
nonlocal flow_added
|
387
|
+
nonlocal function_added
|
388
|
+
if not flow_added:
|
389
|
+
if not function_added:
|
390
|
+
self.add_new_col_text(
|
391
|
+
col_name=RegisterFlag.FUNCTION,
|
392
|
+
val=RegisterFlag.FLOW.value,
|
393
|
+
)
|
394
|
+
function_added = True
|
395
|
+
else:
|
396
|
+
self._edit_row_text(
|
397
|
+
col_name=RegisterFlag.FUNCTION,
|
398
|
+
val=RegisterFlag.FLOW.value,
|
399
|
+
)
|
346
400
|
self.add_new_col_num(
|
347
|
-
col_name=RegisterFlag.
|
348
|
-
val=row.
|
401
|
+
col_name=RegisterFlag.TIMETABLE_FLOW,
|
402
|
+
val=row.flow,
|
349
403
|
)
|
350
|
-
|
351
|
-
|
352
|
-
self.get_num_rows()
|
404
|
+
flow_added = True
|
405
|
+
else:
|
353
406
|
self._edit_row_text(
|
354
407
|
col_name=RegisterFlag.FUNCTION, val=RegisterFlag.FLOW.value
|
355
408
|
)
|
356
|
-
self.add_new_col_num(col_name=RegisterFlag.TIMETABLE_FLOW, val=row.flow)
|
357
409
|
self._edit_row_num(col_name=RegisterFlag.TIMETABLE_FLOW, val=row.flow)
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
410
|
+
|
411
|
+
def add_om():
|
412
|
+
nonlocal om_added
|
413
|
+
nonlocal function_added
|
414
|
+
if not om_added:
|
415
|
+
if not function_added:
|
416
|
+
self.add_new_col_text(
|
417
|
+
col_name=RegisterFlag.FUNCTION,
|
418
|
+
val=RegisterFlag.SOLVENT_COMPOSITION.value,
|
419
|
+
)
|
420
|
+
function_added = True
|
421
|
+
else:
|
422
|
+
self._edit_row_text(
|
423
|
+
col_name=RegisterFlag.FUNCTION,
|
424
|
+
val=RegisterFlag.SOLVENT_COMPOSITION.value,
|
425
|
+
)
|
426
|
+
self.add_new_col_num(
|
427
|
+
col_name=RegisterFlag.TIMETABLE_SOLVENT_B_COMPOSITION,
|
428
|
+
val=row.organic_modifer,
|
429
|
+
)
|
430
|
+
om_added = True
|
431
|
+
else:
|
363
432
|
self._edit_row_text(
|
364
433
|
col_name=RegisterFlag.FUNCTION,
|
365
434
|
val=RegisterFlag.SOLVENT_COMPOSITION.value,
|
366
435
|
)
|
367
|
-
self._edit_row_num(col_name=RegisterFlag.TIME, val=row.start_time)
|
368
436
|
self._edit_row_num(
|
369
437
|
col_name=RegisterFlag.TIMETABLE_SOLVENT_B_COMPOSITION,
|
370
438
|
val=row.organic_modifer,
|
371
439
|
)
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
440
|
+
|
441
|
+
if row.organic_modifer:
|
442
|
+
self.add_row()
|
443
|
+
add_om()
|
444
|
+
add_time()
|
445
|
+
if row.flow:
|
446
|
+
self.add_row()
|
447
|
+
add_flow()
|
448
|
+
add_time()
|
449
|
+
self.download()
|
450
|
+
return time_added, flow_added, om_added, function_added
|
451
|
+
|
452
|
+
# if first_row:
|
453
|
+
# time_added = False
|
454
|
+
# flow_row_method: Callable = (
|
455
|
+
# self.add_new_col_text
|
456
|
+
# if row.flow and not row.organic_modifer
|
457
|
+
# else self._edit_row_text
|
458
|
+
# )
|
459
|
+
# if row.organic_modifer:
|
460
|
+
# self.add_row()
|
461
|
+
# self.add_new_col_text(
|
462
|
+
# col_name=RegisterFlag.FUNCTION,
|
463
|
+
# val=RegisterFlag.SOLVENT_COMPOSITION.value,
|
464
|
+
# )
|
465
|
+
# if not time_added:
|
466
|
+
# time_added = True
|
467
|
+
# self.add_new_col_num(col_name=RegisterFlag.TIME, val=row.start_time)
|
468
|
+
# self.add_new_col_num(
|
469
|
+
# col_name=RegisterFlag.TIMETABLE_SOLVENT_B_COMPOSITION,
|
470
|
+
# val=row.organic_modifer,
|
471
|
+
# )
|
472
|
+
# if row.flow:
|
473
|
+
# self.add_row()
|
474
|
+
# self.get_num_rows()
|
475
|
+
# flow_row_method(
|
476
|
+
# col_name=RegisterFlag.FUNCTION, val=RegisterFlag.FLOW.value
|
477
|
+
# )
|
478
|
+
# if not time_added:
|
479
|
+
# time_added = True
|
480
|
+
# self.add_new_col_num(col_name=RegisterFlag.TIME, val=row.start_time)
|
481
|
+
# self.add_new_col_num(col_name=RegisterFlag.TIMETABLE_FLOW, val=row.flow)
|
482
|
+
# self._edit_row_num(col_name=RegisterFlag.TIMETABLE_FLOW, val=row.flow)
|
483
|
+
# self.download()
|
484
|
+
# else:
|
485
|
+
# if row.organic_modifer:
|
486
|
+
# self.add_row()
|
487
|
+
# self.get_num_rows()
|
488
|
+
# self._edit_row_text(
|
489
|
+
# col_name=RegisterFlag.FUNCTION,
|
490
|
+
# val=RegisterFlag.SOLVENT_COMPOSITION.value,
|
491
|
+
# )
|
492
|
+
# self._edit_row_num(col_name=RegisterFlag.TIME, val=row.start_time)
|
493
|
+
# self._edit_row_num(
|
494
|
+
# col_name=RegisterFlag.TIMETABLE_SOLVENT_B_COMPOSITION,
|
495
|
+
# val=row.organic_modifer,
|
496
|
+
# )
|
497
|
+
# self.download()
|
498
|
+
# if row.flow:
|
499
|
+
# self.add_row()
|
500
|
+
# self.get_num_rows()
|
501
|
+
# self._edit_row_text(
|
502
|
+
# col_name=RegisterFlag.FUNCTION, val=RegisterFlag.FLOW.value
|
503
|
+
# )
|
504
|
+
# self._edit_row_num(col_name=RegisterFlag.TIMETABLE_FLOW, val=row.flow)
|
505
|
+
# self._edit_row_num(col_name=RegisterFlag.TIME, val=row.start_time)
|
506
|
+
# self.download()
|
382
507
|
|
383
508
|
def edit_method_timetable(self, timetable_rows: List[TimeTableEntry]):
|
384
509
|
self.get_num_rows()
|
@@ -389,10 +514,23 @@ class MethodController(RunController):
|
|
389
514
|
res = self.get_num_rows()
|
390
515
|
|
391
516
|
self.new_table()
|
392
|
-
self.get_num_rows()
|
393
|
-
|
517
|
+
num_rows = self.get_num_rows()
|
518
|
+
if num_rows.ok_value.num_response != 0:
|
519
|
+
raise ValueError("Should be zero rows!")
|
520
|
+
|
521
|
+
time_added = False
|
522
|
+
flow_added = False
|
523
|
+
om_added = False
|
524
|
+
function_added = False
|
394
525
|
for i, row in enumerate(timetable_rows):
|
395
|
-
self._edit_row(
|
526
|
+
time_added, flow_added, om_added, function_added = self._edit_row(
|
527
|
+
row=row,
|
528
|
+
first_row=i == 0,
|
529
|
+
time_added=time_added,
|
530
|
+
flow_added=flow_added,
|
531
|
+
om_added=om_added,
|
532
|
+
function_added=function_added,
|
533
|
+
)
|
396
534
|
|
397
535
|
def stop(self):
|
398
536
|
"""
|
@@ -490,3 +628,25 @@ class MethodController(RunController):
|
|
490
628
|
if len(possible_data.x) > 0:
|
491
629
|
signal.data = possible_data
|
492
630
|
return [metd_report]
|
631
|
+
|
632
|
+
def _validate_row(self, row: TimeTableEntry):
|
633
|
+
if not (row.flow or row.organic_modifer):
|
634
|
+
raise ValueError(
|
635
|
+
"Require one of flow or organic modifier for the method timetable entry!"
|
636
|
+
)
|
637
|
+
if row.flow:
|
638
|
+
self._validate_flow(row.flow)
|
639
|
+
if row.organic_modifer:
|
640
|
+
self._validate_organic_modifier(row.organic_modifer)
|
641
|
+
|
642
|
+
def validate_timetable(self, timetable: List[TimeTableEntry]):
|
643
|
+
start_time = 0.0
|
644
|
+
for i, row in enumerate(timetable):
|
645
|
+
if row.start_time > start_time:
|
646
|
+
start_time = row.start_time
|
647
|
+
elif row.start_time <= start_time:
|
648
|
+
raise ValueError(
|
649
|
+
f"""Every row's start time must be larger than the previous start time.
|
650
|
+
Row {i + 1} ({timetable[i].start_time}) has a smaller or equal starttime than row {i} ({start_time})"""
|
651
|
+
)
|
652
|
+
self._validate_row(row)
|
@@ -1,7 +1,9 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
1
3
|
import os
|
2
4
|
import time
|
3
5
|
import warnings
|
4
|
-
from typing import Any, Dict, List, Optional, Union, Set
|
6
|
+
from typing import Any, Dict, List, Optional, Union, Set, Tuple
|
5
7
|
|
6
8
|
from result import Err, Ok, Result
|
7
9
|
from typing_extensions import override
|
@@ -9,6 +11,7 @@ from typing_extensions import override
|
|
9
11
|
from pychemstation.analysis.chromatogram import (
|
10
12
|
AgilentChannelChromatogramData,
|
11
13
|
AgilentHPLCChromatogram,
|
14
|
+
SEQUENCE_TIME_FORMAT,
|
12
15
|
)
|
13
16
|
|
14
17
|
from ....analysis.process_report import AgilentReport, ReportType
|
@@ -118,7 +121,6 @@ class SequenceController(RunController):
|
|
118
121
|
parsed_response = self.get_current_sequence_name()
|
119
122
|
|
120
123
|
assert parsed_response == f"{seq_name}.S", "Switching sequence failed."
|
121
|
-
self.table_state = self.load()
|
122
124
|
|
123
125
|
def get_current_sequence_name(self):
|
124
126
|
self.send(Command.GET_SEQUENCE_CMD)
|
@@ -186,6 +188,8 @@ class SequenceController(RunController):
|
|
186
188
|
def edit_sample_type(
|
187
189
|
self, sample_type: SampleType, row_num: int, save: bool = True
|
188
190
|
):
|
191
|
+
if not isinstance(sample_type, SampleType):
|
192
|
+
raise ValueError("`sample_type` should be of type `SampleType`")
|
189
193
|
self._edit_row_num(
|
190
194
|
row=row_num,
|
191
195
|
col_name=RegisterFlag.SAMPLE_TYPE,
|
@@ -207,6 +211,8 @@ class SequenceController(RunController):
|
|
207
211
|
def edit_injection_source(
|
208
212
|
self, inj_source: InjectionSource, row_num: int, save: bool = True
|
209
213
|
):
|
214
|
+
if not isinstance(inj_source, InjectionSource):
|
215
|
+
raise ValueError("`inj_source` should be of type `InjectionSource`")
|
210
216
|
self._edit_row_text(
|
211
217
|
row=row_num, col_name=RegisterFlag.INJ_SOR, val=inj_source.value
|
212
218
|
)
|
@@ -224,25 +230,65 @@ class SequenceController(RunController):
|
|
224
230
|
|
225
231
|
def edit_num_injections(self, num_inj: int, row_num: int, save: bool = True):
|
226
232
|
self._edit_row_num(row=row_num, col_name=RegisterFlag.NUM_INJ, val=num_inj)
|
233
|
+
if save:
|
234
|
+
self.save()
|
227
235
|
|
228
|
-
def edit_method_name(
|
236
|
+
def edit_method_name(
|
237
|
+
self, method: str, row_num: int, save: bool = True, override_check: bool = False
|
238
|
+
):
|
229
239
|
method_dir = self.method_controller.src
|
230
240
|
possible_path = os.path.join(method_dir, method) + ".M\\"
|
231
241
|
if os.path.exists(possible_path):
|
232
242
|
method = os.path.join(method_dir, method)
|
243
|
+
elif not override_check:
|
244
|
+
raise ValueError(
|
245
|
+
"Method may not exist. If you would still like to use this method, set the `override_check` flag to `True`"
|
246
|
+
)
|
233
247
|
self._edit_row_text(row=row_num, col_name=RegisterFlag.METHOD, val=method)
|
234
248
|
if save:
|
235
249
|
self.save()
|
236
250
|
|
237
251
|
def edit_vial_location(self, loc: Tray, row_num: int, save: bool = True):
|
238
252
|
loc_num = -1
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
253
|
+
try:
|
254
|
+
previous_contents = self.get_row(row_num)
|
255
|
+
if (
|
256
|
+
isinstance(loc, VialBar)
|
257
|
+
and isinstance(previous_contents.vial_location, VialBar)
|
258
|
+
or isinstance(loc, FiftyFourVialPlate)
|
259
|
+
and isinstance(previous_contents.vial_location, FiftyFourVialPlate)
|
260
|
+
):
|
261
|
+
if isinstance(loc, VialBar):
|
262
|
+
loc_num = loc.value
|
263
|
+
elif isinstance(loc, FiftyFourVialPlate):
|
264
|
+
loc_num = loc.value()
|
265
|
+
self._edit_row_num(
|
266
|
+
row=row_num, col_name=RegisterFlag.VIAL_LOCATION, val=loc_num
|
267
|
+
)
|
268
|
+
elif isinstance(loc, VialBar) or isinstance(loc, FiftyFourVialPlate):
|
269
|
+
self.add_row()
|
270
|
+
previous_contents.vial_location = loc
|
271
|
+
num_rows = self.get_num_rows().ok_value.num_response
|
272
|
+
self._edit_row(previous_contents, num_rows)
|
273
|
+
self.move_row(int(num_rows), row_num)
|
274
|
+
self.delete_row(row_num + 1)
|
275
|
+
self.save()
|
276
|
+
else:
|
277
|
+
raise ValueError(
|
278
|
+
"`loc` should be of type `VialBar`, `FiftyFourVialPlate`"
|
279
|
+
)
|
280
|
+
except Exception:
|
281
|
+
if not (isinstance(loc, VialBar) or isinstance(loc, FiftyFourVialPlate)):
|
282
|
+
raise ValueError(
|
283
|
+
"`loc` should be of type `VialBar`, `FiftyFourVialPlate`"
|
284
|
+
)
|
285
|
+
if isinstance(loc, VialBar):
|
286
|
+
loc_num = loc.value
|
287
|
+
elif isinstance(loc, FiftyFourVialPlate):
|
288
|
+
loc_num = loc.value()
|
289
|
+
self._edit_row_num(
|
290
|
+
row=row_num, col_name=RegisterFlag.VIAL_LOCATION, val=loc_num
|
291
|
+
)
|
246
292
|
if save:
|
247
293
|
self.save()
|
248
294
|
|
@@ -284,6 +330,9 @@ class SequenceController(RunController):
|
|
284
330
|
curr_method_runtime = self.method_controller.get_total_runtime()
|
285
331
|
total_runtime += curr_method_runtime
|
286
332
|
|
333
|
+
timestamp = time.strftime(SEQUENCE_TIME_FORMAT)
|
334
|
+
folder_name = f"{self.table_state.name} {timestamp}"
|
335
|
+
|
287
336
|
self.send(Command.RUN_SEQUENCE_CMD.value)
|
288
337
|
self.timeout = total_runtime * 60
|
289
338
|
|
@@ -295,15 +344,7 @@ class SequenceController(RunController):
|
|
295
344
|
break
|
296
345
|
|
297
346
|
if hplc_running:
|
298
|
-
|
299
|
-
for _ in range(5):
|
300
|
-
try:
|
301
|
-
full_path_name, current_sample_file = (
|
302
|
-
self.get_current_run_data_dir_file()
|
303
|
-
)
|
304
|
-
break
|
305
|
-
except ValueError:
|
306
|
-
pass
|
347
|
+
current_sample_file, full_path_name = self.try_getting_run_info(folder_name)
|
307
348
|
if full_path_name and current_sample_file:
|
308
349
|
data_file = SequenceDataFiles(
|
309
350
|
sequence_name=self.table_state.name,
|
@@ -324,6 +365,36 @@ class SequenceController(RunController):
|
|
324
365
|
else:
|
325
366
|
raise RuntimeError("Sequence run may not have started.")
|
326
367
|
|
368
|
+
def try_getting_run_info(self, folder_name: str) -> Tuple[str, str | None]:
|
369
|
+
full_path_name, current_sample_file = None, None
|
370
|
+
for _ in range(5):
|
371
|
+
try:
|
372
|
+
full_path_name, current_sample_file = (
|
373
|
+
self.get_current_run_data_dir_file()
|
374
|
+
)
|
375
|
+
except ValueError:
|
376
|
+
pass
|
377
|
+
if full_path_name and folder_name in full_path_name:
|
378
|
+
pass
|
379
|
+
else:
|
380
|
+
if self.controller:
|
381
|
+
self.controller.send(Command.GET_RUNNING_SEQUENCE_DIR)
|
382
|
+
res = self.controller.receive()
|
383
|
+
if res.is_ok():
|
384
|
+
if os.path.isdir(res.ok_value.string_response):
|
385
|
+
if folder_name in res.ok_value.string_response:
|
386
|
+
full_path_name = res.ok_value.string_response
|
387
|
+
else:
|
388
|
+
raise ValueError("Could not get sequence data folder.")
|
389
|
+
else:
|
390
|
+
raise ValueError("Controller is offline.")
|
391
|
+
if current_sample_file and full_path_name:
|
392
|
+
return full_path_name, current_sample_file
|
393
|
+
elif full_path_name:
|
394
|
+
return full_path_name, None
|
395
|
+
else:
|
396
|
+
raise ValueError("Could not get sequence data folder")
|
397
|
+
|
327
398
|
@override
|
328
399
|
def _fuzzy_match_most_recent_folder(
|
329
400
|
self, most_recent_folder: T, child_dirs: Optional[Set[str]]
|
@@ -338,8 +409,13 @@ class SequenceController(RunController):
|
|
338
409
|
and set(most_recent_folder._data_files) == child_dirs
|
339
410
|
):
|
340
411
|
most_recent_folder.child_dirs = [
|
341
|
-
os.path.join(most_recent_folder.dir, f)
|
412
|
+
os.path.join(most_recent_folder.dir, f)
|
413
|
+
if not os.path.isdir(f)
|
414
|
+
else f
|
415
|
+
for f in child_dirs
|
342
416
|
]
|
417
|
+
for d in most_recent_folder.child_dirs:
|
418
|
+
assert os.path.isdir(d)
|
343
419
|
else:
|
344
420
|
potential_folders: List[str] = sorted(
|
345
421
|
list(
|
@@ -427,6 +503,13 @@ class SequenceController(RunController):
|
|
427
503
|
).ok_value
|
428
504
|
)
|
429
505
|
parent_dir = self.data_files[-1]
|
506
|
+
if (
|
507
|
+
len(parent_dir._data_files) != len(parent_dir.child_dirs)
|
508
|
+
or len(parent_dir.child_dirs) == 0
|
509
|
+
):
|
510
|
+
parent_dir = self._fuzzy_match_most_recent_folder(
|
511
|
+
most_recent_folder=parent_dir, child_dirs=None
|
512
|
+
)
|
430
513
|
spectra = self.get_data()
|
431
514
|
reports = []
|
432
515
|
for i, child_dir in enumerate(parent_dir.child_dirs):
|
pychemstation/control/hplc.py
CHANGED
@@ -20,7 +20,7 @@ from ..control.controllers import CommunicationController
|
|
20
20
|
from ..utils.injector_types import InjectorTable
|
21
21
|
from ..utils.macro import Command, Response, Status
|
22
22
|
from ..utils.method_types import MethodDetails
|
23
|
-
from ..utils.sequence_types import SequenceTable
|
23
|
+
from ..utils.sequence_types import SequenceTable, SequenceDataFiles
|
24
24
|
from ..utils.table_types import Table
|
25
25
|
|
26
26
|
|
@@ -107,7 +107,11 @@ class HPLCController:
|
|
107
107
|
raise RuntimeError(
|
108
108
|
"Communication controller must be initialized before sending command. It is currently in offline mode."
|
109
109
|
)
|
110
|
-
|
110
|
+
res = self.comm.receive()
|
111
|
+
if res.is_ok():
|
112
|
+
return res.ok_value
|
113
|
+
else:
|
114
|
+
return res.err_value
|
111
115
|
|
112
116
|
def status(self) -> Status:
|
113
117
|
"""Get the current status of the HPLC machine.
|
@@ -202,6 +206,16 @@ class HPLCController:
|
|
202
206
|
"""
|
203
207
|
self.sequence_controller.edit(updated_sequence)
|
204
208
|
|
209
|
+
def get_last_run_method_file_path(self) -> str:
|
210
|
+
"""Get the folder (ending with .D) for last run method.
|
211
|
+
|
212
|
+
:return: Complete path for method run.
|
213
|
+
"""
|
214
|
+
if len(self.method_controller.data_files) > 0:
|
215
|
+
return self.method_controller.data_files[-1]
|
216
|
+
else:
|
217
|
+
raise UserWarning("No data yet!")
|
218
|
+
|
205
219
|
def get_last_run_method_report(
|
206
220
|
self,
|
207
221
|
custom_path: Optional[str] = None,
|
@@ -230,6 +244,20 @@ class HPLCController:
|
|
230
244
|
else:
|
231
245
|
return self.method_controller.get_data(custom_path=custom_path)
|
232
246
|
|
247
|
+
def get_last_run_sequence_file_paths(self) -> SequenceDataFiles:
|
248
|
+
"""Get the sequence folder and all run folders (ending with .D).
|
249
|
+
|
250
|
+
:return: `SequenceDataFiles` containing complete path locations for sequence folder and all runs.
|
251
|
+
"""
|
252
|
+
if len(self.sequence_controller.data_files):
|
253
|
+
self.sequence_controller._fuzzy_match_most_recent_folder(
|
254
|
+
most_recent_folder=self.sequence_controller.data_files[-1],
|
255
|
+
child_dirs=set(),
|
256
|
+
)
|
257
|
+
return self.sequence_controller.data_files[-1]
|
258
|
+
else:
|
259
|
+
raise UserWarning("No data files yet!")
|
260
|
+
|
233
261
|
def get_last_run_sequence_reports(
|
234
262
|
self,
|
235
263
|
custom_path: Optional[str] = None,
|
@@ -255,9 +255,14 @@ class RunController(ABCTableController, abc.ABC):
|
|
255
255
|
self.send(Command.GET_CURRENT_RUN_DATA_FILE)
|
256
256
|
current_sample_file = self.receive()
|
257
257
|
if full_path_name.is_ok() and current_sample_file.is_ok():
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
258
|
+
if os.path.isdir(full_path_name.ok_value.string_response) and os.path.isdir(
|
259
|
+
os.path.join(
|
260
|
+
full_path_name.ok_value.string_response,
|
261
|
+
current_sample_file.ok_value.string_response,
|
262
|
+
)
|
263
|
+
):
|
264
|
+
return (
|
265
|
+
full_path_name.ok_value.string_response,
|
266
|
+
current_sample_file.ok_value.string_response,
|
267
|
+
)
|
268
|
+
raise ValueError("Couldn't read data dir and file or doesn't exist yet.")
|
@@ -126,8 +126,8 @@ class ABCTableController(abc.ABC):
|
|
126
126
|
):
|
127
127
|
if not (isinstance(val, int) or isinstance(val, float)):
|
128
128
|
raise ValueError(f"{val} must be an int or float.")
|
129
|
+
num_rows = self.get_num_rows()
|
129
130
|
if row:
|
130
|
-
num_rows = self.get_num_rows()
|
131
131
|
if num_rows.is_ok():
|
132
132
|
if num_rows.ok_value.num_response < row:
|
133
133
|
raise ValueError("Not enough rows to edit!")
|
@@ -136,7 +136,7 @@ class ABCTableController(abc.ABC):
|
|
136
136
|
TableOperation.EDIT_ROW_VAL.value.format(
|
137
137
|
register=self.table_locator.register,
|
138
138
|
table_name=self.table_locator.name,
|
139
|
-
row=row if row is not None else "
|
139
|
+
row=row if row is not None else "response_num",
|
140
140
|
col_name=col_name,
|
141
141
|
val=val,
|
142
142
|
)
|
@@ -147,8 +147,8 @@ class ABCTableController(abc.ABC):
|
|
147
147
|
):
|
148
148
|
if not isinstance(val, str):
|
149
149
|
raise ValueError(f"{val} must be a str.")
|
150
|
+
num_rows = self.get_num_rows()
|
150
151
|
if row:
|
151
|
-
num_rows = self.get_num_rows()
|
152
152
|
if num_rows.is_ok():
|
153
153
|
if num_rows.ok_value.num_response < row:
|
154
154
|
raise ValueError("Not enough rows to edit!")
|
@@ -157,7 +157,7 @@ class ABCTableController(abc.ABC):
|
|
157
157
|
TableOperation.EDIT_ROW_TEXT.value.format(
|
158
158
|
register=self.table_locator.register,
|
159
159
|
table_name=self.table_locator.name,
|
160
|
-
row=row if row is not None else "
|
160
|
+
row=row if row is not None else "response_num",
|
161
161
|
col_name=col_name,
|
162
162
|
val=val,
|
163
163
|
)
|
@@ -178,11 +178,15 @@ class ABCTableController(abc.ABC):
|
|
178
178
|
|
179
179
|
def add_row(self):
|
180
180
|
"""Adds a row to the provided table for currently loaded method or sequence."""
|
181
|
+
previous_row_count = self.get_num_rows().ok_value.num_response
|
181
182
|
self.sleepy_send(
|
182
183
|
TableOperation.NEW_ROW.value.format(
|
183
184
|
register=self.table_locator.register, table_name=self.table_locator.name
|
184
185
|
)
|
185
186
|
)
|
187
|
+
new_row_count = self.get_num_rows().ok_value.num_response
|
188
|
+
if previous_row_count + 1 != new_row_count:
|
189
|
+
raise ValueError("Row could not be added.")
|
186
190
|
|
187
191
|
def delete_table(self):
|
188
192
|
"""Deletes the table."""
|
@@ -201,13 +205,6 @@ class ABCTableController(abc.ABC):
|
|
201
205
|
)
|
202
206
|
|
203
207
|
def get_num_rows(self) -> Result[Response, str]:
|
204
|
-
self.send(
|
205
|
-
TableOperation.GET_NUM_ROWS.value.format(
|
206
|
-
register=self.table_locator.register,
|
207
|
-
table_name=self.table_locator.name,
|
208
|
-
col_name=RegisterFlag.NUM_ROWS,
|
209
|
-
)
|
210
|
-
)
|
211
208
|
self.send(
|
212
209
|
Command.GET_ROWS_CMD.value.format(
|
213
210
|
register=self.table_locator.register,
|
@@ -221,8 +218,16 @@ class ABCTableController(abc.ABC):
|
|
221
218
|
raise ValueError("Controller is offline")
|
222
219
|
|
223
220
|
if res.is_ok():
|
224
|
-
self.send("Sleep 0.1")
|
225
|
-
self.send("Print Rows")
|
226
221
|
return res
|
227
222
|
else:
|
228
223
|
return Err("No rows could be read.")
|
224
|
+
|
225
|
+
def move_row(self, from_row: int, to_row: int):
|
226
|
+
self.send(
|
227
|
+
TableOperation.MOVE_ROW.value.format(
|
228
|
+
register=self.table_locator.register,
|
229
|
+
table_name=self.table_locator.name,
|
230
|
+
from_row=from_row,
|
231
|
+
to_row=to_row,
|
232
|
+
)
|
233
|
+
)
|
pychemstation/utils/macro.py
CHANGED
@@ -55,12 +55,15 @@ class Command(Enum):
|
|
55
55
|
# Get directories
|
56
56
|
GET_METHOD_DIR = "response$ = _METHPATH$"
|
57
57
|
GET_SEQUENCE_DIR = "response$ = _SEQUENCEPATHS$"
|
58
|
+
CONFIG_MET_PATH = "_CONFIGMETPATH"
|
59
|
+
CONFIG_SEQ_PATH = "_CONFIGSEQPATH"
|
60
|
+
GET_RUNNING_SEQUENCE_DIR = "response$ = _SEQPATHS$"
|
58
61
|
GET_DATA_DIRS = "response$ = _DATAPATHS$"
|
59
62
|
GET_CURRENT_RUN_DATA_DIR = "response$ = _DATAPath$"
|
60
63
|
GET_CURRENT_RUN_DATA_FILE = "response$ = _DATAFILE1$"
|
61
64
|
|
62
|
-
#
|
63
|
-
ERROR = "response$ =
|
65
|
+
# Errors
|
66
|
+
ERROR = "response$ = _ERRMSG$"
|
64
67
|
|
65
68
|
|
66
69
|
class HPLCRunningStatus(Enum):
|
@@ -1,5 +1,28 @@
|
|
1
|
-
from
|
1
|
+
from typing import Union
|
2
|
+
|
3
|
+
from result import Result
|
4
|
+
|
5
|
+
from .mock_hplc import MockHPLC
|
6
|
+
from ..abc_tables.abc_comm import ABCCommunicationController
|
7
|
+
from ..macro import Status
|
2
8
|
|
3
9
|
|
4
10
|
class MockCommunicationController(ABCCommunicationController):
|
5
|
-
|
11
|
+
def __init__(self, comm_dir: str):
|
12
|
+
super().__init__(comm_dir)
|
13
|
+
self.hplc = MockHPLC()
|
14
|
+
|
15
|
+
def get_num_val(self, cmd: str) -> Union[int, float]:
|
16
|
+
raise NotImplementedError
|
17
|
+
|
18
|
+
def get_text_val(self, cmd: str) -> str:
|
19
|
+
raise NotImplementedError
|
20
|
+
|
21
|
+
def get_status(self) -> Status:
|
22
|
+
raise NotImplementedError
|
23
|
+
|
24
|
+
def _send(self, cmd: str, cmd_no: int, num_attempts=5) -> None:
|
25
|
+
raise NotImplementedError
|
26
|
+
|
27
|
+
def _receive(self, cmd_no: int, num_attempts=100) -> Result[str, str]:
|
28
|
+
raise NotImplementedError
|
@@ -1,2 +1,30 @@
|
|
1
|
+
from ..macro import HPLCAvailStatus, Status
|
2
|
+
from ..method_types import MethodDetails, HPLCMethodParams, TimeTableEntry
|
3
|
+
from ..sequence_types import SequenceTable, SequenceEntry, InjectionSource
|
4
|
+
from ..tray_types import FiftyFourVialPlate
|
5
|
+
|
6
|
+
|
1
7
|
class MockHPLC:
|
2
|
-
|
8
|
+
def __init__(self):
|
9
|
+
self.current_method: MethodDetails = MethodDetails(
|
10
|
+
name="General-Poroshell",
|
11
|
+
params=HPLCMethodParams(organic_modifier=5, flow=0.65),
|
12
|
+
timetable=[TimeTableEntry(start_time=3, organic_modifer=99, flow=0.65)],
|
13
|
+
stop_time=5,
|
14
|
+
post_time=2,
|
15
|
+
)
|
16
|
+
self.current_sequence: SequenceTable = SequenceTable(
|
17
|
+
name="hplc_testing",
|
18
|
+
rows=[
|
19
|
+
SequenceEntry(
|
20
|
+
vial_location=FiftyFourVialPlate.from_str("P1-A2"),
|
21
|
+
sample_name="sample1",
|
22
|
+
data_file="sample1",
|
23
|
+
method="General-Poroshell",
|
24
|
+
num_inj=1,
|
25
|
+
inj_vol=1,
|
26
|
+
inj_source=InjectionSource.HIP_ALS,
|
27
|
+
)
|
28
|
+
],
|
29
|
+
)
|
30
|
+
self.current_status: Status = HPLCAvailStatus.STANDBY
|
@@ -16,6 +16,8 @@ class TableOperation(Enum):
|
|
16
16
|
DELETE_TABLE = 'DelTab {register}, "{table_name}"'
|
17
17
|
CREATE_TABLE = 'NewTab {register}, "{table_name}"'
|
18
18
|
NEW_ROW = 'InsTabRow {register}, "{table_name}"'
|
19
|
+
NEW_ROW_SPECIFIC = 'InsTabRow {register}, "{table_name}"'
|
20
|
+
MOVE_ROW = 'MoveTabRow {register}, "{table_name}", {from_row}, {to_row}'
|
19
21
|
DELETE_ROW = 'DelTabRow {register}, "{table_name}", {row}'
|
20
22
|
EDIT_ROW_VAL = 'SetTabVal "{register}", "{table_name}", {row}, "{col_name}", {val}'
|
21
23
|
EDIT_ROW_TEXT = (
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: pychemstation
|
3
|
-
Version: 0.10.8.
|
3
|
+
Version: 0.10.8.dev3
|
4
4
|
Summary: Library to interact with Chemstation software, primarily used in Hein lab
|
5
5
|
Project-URL: Documentation, https://pychemstation-e5a086.gitlab.io/pychemstation.html
|
6
6
|
Project-URL: Repository, https://gitlab.com/heingroup/device-api/pychemstation
|
@@ -5,13 +5,13 @@ pychemstation/analysis/chromatogram.py,sha256=Jk6xOMHA6kSV597fJDZgrFRlvVorldvK4z
|
|
5
5
|
pychemstation/analysis/process_report.py,sha256=aTsW6u5-0iwsH3jQtkoKE9jbsy5NAUG6l7O-I49B8kY,14650
|
6
6
|
pychemstation/control/README.md,sha256=ohPn3xhgjFyPraQqR4x9aZhurQVAOYuYHv-E8sj0eK4,3124
|
7
7
|
pychemstation/control/__init__.py,sha256=7lSkY7Qa7Ikdz82-2FESc_oqktv7JndsjltCkiMqnMI,147
|
8
|
-
pychemstation/control/hplc.py,sha256=
|
8
|
+
pychemstation/control/hplc.py,sha256=JrfkQ5Jt9K9kf5l2X5wQzuYaQvPEnDa_aAkCVeMBk0o,14244
|
9
9
|
pychemstation/control/controllers/README.md,sha256=S5cd4NJmPjs6TUH98BtPJJhiS1Lu-mxLCNS786ogOrQ,32
|
10
10
|
pychemstation/control/controllers/__init__.py,sha256=q2TUEie3J-OLlxcGLkG7vIy8fazCEhHm61OGzJPbhD0,179
|
11
11
|
pychemstation/control/controllers/comm.py,sha256=ySjgMBIfJ11sygXiZSPp9Rf6ABM4t6JhZRONRj1u2Cc,6652
|
12
12
|
pychemstation/control/controllers/data_aq/__init__.py,sha256=w-Zgbit10niOQfz780ZmRHjUFxV1hMkdui7fOMPqeLA,132
|
13
|
-
pychemstation/control/controllers/data_aq/method.py,sha256=
|
14
|
-
pychemstation/control/controllers/data_aq/sequence.py,sha256=
|
13
|
+
pychemstation/control/controllers/data_aq/method.py,sha256=KFKL8yt3lHxpgND52z4gN6TeMvnNaAOVetpO2su1GlU,24935
|
14
|
+
pychemstation/control/controllers/data_aq/sequence.py,sha256=CgNPc-IaPXCHkkWjhb2UrxhDmAltUz7rPCiZa4O6ATw,20967
|
15
15
|
pychemstation/control/controllers/devices/__init__.py,sha256=QpgGnLXyWiB96KIB98wMccEi8oOUUaLxvBCyevJzcOg,75
|
16
16
|
pychemstation/control/controllers/devices/injector.py,sha256=LyubM-fqf5ruseGx32deTDK-yevmaTOvdo6YKg2PF7I,4029
|
17
17
|
pychemstation/generated/__init__.py,sha256=xnEs0QTjeuGYO3tVUIy8GDo95GqTV1peEjosGckpOu0,977
|
@@ -19,23 +19,23 @@ pychemstation/generated/dad_method.py,sha256=xTUiSCvkXcxBUhjVm1YZKu-tHs16k23pF-0
|
|
19
19
|
pychemstation/generated/pump_method.py,sha256=s3MckKDw2-nZUC5lHrJVvXYdneWP8-9UvblNuGryPHY,12092
|
20
20
|
pychemstation/utils/__init__.py,sha256=GZJyDzkhzrlMguxZTUpgthq72pA3YV23DJIR2Q63PCk,449
|
21
21
|
pychemstation/utils/injector_types.py,sha256=z2iWwTklGm0GRDCL9pnPCovQrwyRwxv8w5w5Xh7Pj3U,1152
|
22
|
-
pychemstation/utils/macro.py,sha256=
|
23
|
-
pychemstation/utils/method_types.py,sha256=
|
22
|
+
pychemstation/utils/macro.py,sha256=VGOU380ruJSKQhXJFI1g--qg4Xgx-e0D8z5FDPGe0cA,3433
|
23
|
+
pychemstation/utils/method_types.py,sha256=ck8I4dRGhHXCUfBf3AT1OU1eCcSSZPgnlhvlLTfezEM,1562
|
24
24
|
pychemstation/utils/num_utils.py,sha256=OpqZwMPoxTYkpjpinA1CcoQAXDY_0sie6d-hTU547uo,2087
|
25
25
|
pychemstation/utils/parsing.py,sha256=mzdpxrH5ux4-_i4CwZvnIYnIwAnRnOptKb3fZyYJcx0,9307
|
26
26
|
pychemstation/utils/sequence_types.py,sha256=JLGL7kCkPouHN7iBsnZfWe-nSjzF8XqFKzBPyF4SulE,2724
|
27
27
|
pychemstation/utils/spec_utils.py,sha256=BtXgQndZy4kVKsrgEDxwNd0HctypnAt5upB9SOk1D9w,9700
|
28
|
-
pychemstation/utils/table_types.py,sha256=
|
28
|
+
pychemstation/utils/table_types.py,sha256=ZmV52Vl1cYG_C1PEmVGB02mC3Dhfi7QMkUZwe0ujzAg,3748
|
29
29
|
pychemstation/utils/tray_types.py,sha256=UeHM0hUYaNc9giT96ZiGpyWBPQwG-SyLA0rVGzDDAJk,6618
|
30
30
|
pychemstation/utils/abc_tables/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
31
|
-
pychemstation/utils/abc_tables/abc_comm.py,sha256=
|
31
|
+
pychemstation/utils/abc_tables/abc_comm.py,sha256=gLvCiD8hDHXlMsiUzZX__g2kgFCeNnUIK7_nsLwI7Hc,5465
|
32
32
|
pychemstation/utils/abc_tables/device.py,sha256=v8MNFvymbKe4hWsqzO6Z_qsVvju_rISYtnPgaftecyE,919
|
33
|
-
pychemstation/utils/abc_tables/run.py,sha256=
|
34
|
-
pychemstation/utils/abc_tables/table.py,sha256=
|
33
|
+
pychemstation/utils/abc_tables/run.py,sha256=Sr6Iz_YrwJ78HTNHFv6fTA-Kca8gP3Dic_-7-AriyOw,10140
|
34
|
+
pychemstation/utils/abc_tables/table.py,sha256=AbuitDcBHODV-KpxjL7ZPoE-TSa6gyG2uqXXY90Mv2o,7992
|
35
35
|
pychemstation/utils/mocking/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
36
|
-
pychemstation/utils/mocking/mock_comm.py,sha256=
|
37
|
-
pychemstation/utils/mocking/mock_hplc.py,sha256=
|
38
|
-
pychemstation-0.10.8.
|
39
|
-
pychemstation-0.10.8.
|
40
|
-
pychemstation-0.10.8.
|
41
|
-
pychemstation-0.10.8.
|
36
|
+
pychemstation/utils/mocking/mock_comm.py,sha256=vZeYBXaKBZOlJmhn4TSbkov62gqlkfztqf3MSFU9kLE,800
|
37
|
+
pychemstation/utils/mocking/mock_hplc.py,sha256=esVIlU4oqEsYLPOQs0AeVnKv9l52xBGT6UY862l9RQE,1163
|
38
|
+
pychemstation-0.10.8.dev3.dist-info/METADATA,sha256=v0QV6RM1Zumdp8W0qD8rNuy-O-b_Uov8uFcDBsA1FK4,5757
|
39
|
+
pychemstation-0.10.8.dev3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
40
|
+
pychemstation-0.10.8.dev3.dist-info/licenses/LICENSE,sha256=9bdF75gIf1MecZ7oymqWgJREVz7McXPG-mjqrTmzzD8,18658
|
41
|
+
pychemstation-0.10.8.dev3.dist-info/RECORD,,
|
File without changes
|
{pychemstation-0.10.8.dev1.dist-info → pychemstation-0.10.8.dev3.dist-info}/licenses/LICENSE
RENAMED
File without changes
|