pychemstation 0.7.0.dev1__py3-none-any.whl → 0.8.0__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 (49) hide show
  1. pychemstation/analysis/base_spectrum.py +3 -6
  2. pychemstation/analysis/process_report.py +248 -225
  3. pychemstation/analysis/utils.py +3 -1
  4. pychemstation/control/README.md +124 -0
  5. pychemstation/control/controllers/README.md +1 -0
  6. pychemstation/control/controllers/__init__.py +0 -2
  7. pychemstation/control/controllers/comm.py +27 -20
  8. pychemstation/control/controllers/devices/device.py +17 -4
  9. pychemstation/control/controllers/tables/method.py +57 -39
  10. pychemstation/control/controllers/tables/sequence.py +98 -31
  11. pychemstation/control/controllers/tables/table.py +121 -126
  12. pychemstation/control/hplc.py +82 -37
  13. pychemstation/generated/dad_method.py +3 -3
  14. pychemstation/generated/pump_method.py +7 -7
  15. pychemstation/out.txt +145 -0
  16. pychemstation/tests.ipynb +310 -0
  17. pychemstation/utils/chromatogram.py +5 -1
  18. pychemstation/utils/injector_types.py +2 -2
  19. pychemstation/utils/macro.py +1 -1
  20. pychemstation/utils/table_types.py +3 -0
  21. pychemstation/utils/tray_types.py +59 -39
  22. {pychemstation-0.7.0.dev1.dist-info → pychemstation-0.8.0.dist-info}/METADATA +25 -21
  23. pychemstation-0.8.0.dist-info/RECORD +39 -0
  24. {pychemstation-0.7.0.dev1.dist-info → pychemstation-0.8.0.dist-info}/WHEEL +1 -2
  25. pychemstation/control/comm.py +0 -206
  26. pychemstation/control/controllers/devices/column.py +0 -12
  27. pychemstation/control/controllers/devices/dad.py +0 -0
  28. pychemstation/control/controllers/devices/pump.py +0 -43
  29. pychemstation/control/controllers/method.py +0 -338
  30. pychemstation/control/controllers/sequence.py +0 -190
  31. pychemstation/control/controllers/table_controller.py +0 -266
  32. pychemstation/control/table/__init__.py +0 -3
  33. pychemstation/control/table/method.py +0 -274
  34. pychemstation/control/table/sequence.py +0 -210
  35. pychemstation/control/table/table_controller.py +0 -201
  36. pychemstation-0.7.0.dev1.dist-info/RECORD +0 -58
  37. pychemstation-0.7.0.dev1.dist-info/top_level.txt +0 -2
  38. tests/__init__.py +0 -0
  39. tests/constants.py +0 -88
  40. tests/test_comb.py +0 -136
  41. tests/test_comm.py +0 -65
  42. tests/test_inj.py +0 -39
  43. tests/test_method.py +0 -99
  44. tests/test_nightly.py +0 -80
  45. tests/test_proc_rep.py +0 -52
  46. tests/test_runs_stable.py +0 -125
  47. tests/test_sequence.py +0 -125
  48. tests/test_stable.py +0 -283
  49. {pychemstation-0.7.0.dev1.dist-info → pychemstation-0.8.0.dist-info/licenses}/LICENSE +0 -0
@@ -1,6 +1,5 @@
1
1
  from __future__ import annotations
2
2
 
3
- import math
4
3
  from dataclasses import dataclass
5
4
  from enum import Enum
6
5
  from typing import Union
@@ -18,28 +17,23 @@ class Num(Enum):
18
17
  NINE = 9
19
18
 
20
19
  @classmethod
21
- def from_num(cls, num: int) -> Num:
22
- match num:
23
- case 1:
24
- return Num.ONE
25
- case 2:
26
- return Num.TWO
27
- case 3:
28
- return Num.THREE
29
- case 4:
30
- return Num.FOUR
31
- case 5:
32
- return Num.FIVE
33
- case 6:
34
- return Num.SIX
35
- case 7:
36
- return Num.SEVEN
37
- case 8:
38
- return Num.EIGHT
39
- case 9:
40
- return Num.NINE
41
- case _:
42
- raise ValueError("Num is one of 1 to 9")
20
+ def from_num(cls, num: int):
21
+ num_mapping = {
22
+ 1: Num.ONE,
23
+ 2: Num.TWO,
24
+ 3: Num.THREE,
25
+ 4: Num.FOUR,
26
+ 5: Num.FIVE,
27
+ 6: Num.SIX,
28
+ 7: Num.SEVEN,
29
+ 8: Num.EIGHT,
30
+ 9: Num.NINE
31
+ }
32
+
33
+ if num in num_mapping:
34
+ return num_mapping[num]
35
+ else:
36
+ raise ValueError("Num must be between 1 and 9")
43
37
 
44
38
 
45
39
  class Plate(Enum):
@@ -63,25 +57,32 @@ class Letter(Enum):
63
57
 
64
58
  @classmethod
65
59
  def from_str(cls, let: str) -> Letter:
66
- match let:
67
- case "A":
68
- return Letter.A
69
- case "B":
70
- return Letter.B
71
- case "C":
72
- return Letter.C
73
- case "D":
74
- return Letter.D
75
- case "E":
76
- return Letter.E
77
- case "F":
78
- return Letter.F
79
- case _:
80
- raise ValueError("Letter is one of A to F")
60
+ letter_mapping = {
61
+ "A": Letter.A,
62
+ "B": Letter.B,
63
+ "C": Letter.C,
64
+ "D": Letter.D,
65
+ "E": Letter.E,
66
+ "F": Letter.F
67
+ }
68
+
69
+ if let in letter_mapping:
70
+ return letter_mapping[let]
71
+ else:
72
+ raise ValueError("Letter must be one of A to F")
81
73
 
82
74
 
83
75
  @dataclass
84
76
  class FiftyFourVialPlate:
77
+ """
78
+ Class to represent the 54 vial tray. Assumes you have:
79
+ 2 plates (P1 or P2)
80
+ 6 rows (A B C D E F)
81
+ 9 columns (1 2 3 4 5 6 7 8 9)
82
+
83
+ valid vial locations: P1-A2, P2-F9
84
+ invalid vial locations: P3-A1, P1-Z3, P2-B10
85
+ """
85
86
  plate: Plate
86
87
  letter: Letter
87
88
  num: Num
@@ -91,6 +92,12 @@ class FiftyFourVialPlate:
91
92
 
92
93
  @classmethod
93
94
  def from_str(cls, loc: str):
95
+ """
96
+ Converts a string representing the vial location into numerical representation for Chemstation.
97
+ :param loc: vial location
98
+ :returns: `FiftyFourVialPlate` object representing the vial location
99
+ :raises: ValueError if string is invalid tray location
100
+ """
94
101
  if len(loc) != 5:
95
102
  raise ValueError("Plate locations must be PX-LY, where X is either 1 or 2 and Y is 1 to 9")
96
103
  try:
@@ -104,7 +111,17 @@ class FiftyFourVialPlate:
104
111
  raise ValueError("Plate locations must be PX-LY, where X is either 1 or 2 and Y is 1 to 9")
105
112
 
106
113
  @classmethod
107
- def from_int(cls, num: int) -> FiftyFourVialPlate:
114
+ def from_int(cls, num: int) -> Tray:
115
+ """
116
+ Converts an integer representation of a vial location to a `FiftyFourVialPlate` or `TenVialColumn` object
117
+
118
+ :param num: numerical representation of a vial location
119
+ :returns: the proper vial location object
120
+ :raises: ValueError no matching can be made
121
+ """
122
+ if num in range(1, 11):
123
+ return TenVialColumn(num)
124
+
108
125
  row_starts = [
109
126
  # plate 1
110
127
  FiftyFourVialPlate.from_str('P1-F1'),
@@ -148,6 +165,9 @@ class FiftyFourVialPlate:
148
165
 
149
166
 
150
167
  class TenVialColumn(Enum):
168
+ """
169
+ Class to represent the 10 vial locations.
170
+ """
151
171
  ONE = 1
152
172
  TWO = 2
153
173
  THREE = 3
@@ -1,21 +1,24 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: pychemstation
3
- Version: 0.7.0.dev1
4
- Summary: Library to interact with Chemstation software, primarily used in Hein lab
5
- Home-page: https://gitlab.com/heingroup/device-api/pychemstation
6
- Author: Lucy Hao
7
- Author-email: lhao03@student.ubc.ca
8
- Classifier: Programming Language :: Python :: 3
9
- Classifier: License :: OSI Approved :: MIT License
10
- Classifier: Operating System :: OS Independent
11
- Description-Content-Type: text/markdown
3
+ Version: 0.8.0
4
+ Author-email: lucyhao <hao.lucyy@gmail.com>
12
5
  License-File: LICENSE
13
- Requires-Dist: polling
14
- Requires-Dist: seabreeze
15
- Requires-Dist: xsdata
16
- Requires-Dist: result
17
- Requires-Dist: rainbow-api
18
- Requires-Dist: aghplctools==4.8.6
6
+ Requires-Python: >=3.8
7
+ Requires-Dist: aghplctools>=4.8.8
8
+ Requires-Dist: coverage>=7.6.1
9
+ Requires-Dist: matplotlib>=3.7.5
10
+ Requires-Dist: pandas>=2.0.3
11
+ Requires-Dist: pdoc>=14.7.0
12
+ Requires-Dist: polling>=0.3.2
13
+ Requires-Dist: pytest>=7.3.5
14
+ Requires-Dist: rainbow-api>=1.0.10
15
+ Requires-Dist: result>=0.17.0
16
+ Requires-Dist: scipy>=1.10.1
17
+ Requires-Dist: seabreeze>=2.9.2
18
+ Requires-Dist: setuptools>=75.3.2
19
+ Requires-Dist: twine>=6.1.0
20
+ Requires-Dist: xsdata>=24.9
21
+ Description-Content-Type: text/markdown
19
22
 
20
23
  # Agilent HPLC Macro Control
21
24
 
@@ -67,13 +70,14 @@ from pychemstation.control import HPLCController
67
70
  import pandas as pd
68
71
 
69
72
  # these paths will be unique to your Chemstation setup
70
- DEFAULT_COMMAND_PATH = "C:\\Users\\User\\Desktop\\Lucy\\"
71
73
  DEFAULT_METHOD = "GENERAL-POROSHELL"
74
+ DEFAULT_COMMAND_PATH = "C:\\Users\\User\\Desktop\\Lucy\\"
72
75
  DEFAULT_METHOD_DIR = "C:\\ChemStation\\1\\Methods\\"
73
- DATA_DIR = "C:\\Users\\Public\\Documents\\ChemStation\\2\\Data"
74
- SEQUENCE_DIR = "C:\\USERS\\PUBLIC\\DOCUMENTS\\CHEMSTATION\\2\\Sequence"
76
+ DATA_DIR_2 = "C:\\Users\\Public\\Documents\\ChemStation\\2\\Data\\"
77
+ DATA_DIR_3 = "C:\\Users\\Public\\Documents\\ChemStation\\3\\Data\\"
78
+ SEQUENCE_DIR = "C:\\USERS\\PUBLIC\\DOCUMENTS\\CHEMSTATION\\2\\Sequence\\"
75
79
 
76
- hplc_controller = HPLCController(data_dir=DATA_DIR,
80
+ hplc_controller = HPLCController(data_dirs=[DATA_DIR_2, DATA_DIR_3],
77
81
  comm_dir=DEFAULT_COMMAND_PATH,
78
82
  sequence_dir=SEQUENCE_DIR,
79
83
  method_dir=DEFAULT_METHOD_DIR)
@@ -107,4 +111,4 @@ Lucy Hao, Maria Politi
107
111
  Group. Copyright © Cronin Group, used under the [CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/) license.
108
112
  - Adapted from the [MACROS](https://github.com/Bourne-Group/HPLCMethodOptimisationGUI)
109
113
  used in [**Operator-free HPLC automated method development guided by Bayesian optimization**](https://pubs.rsc.org/en/content/articlelanding/2024/dd/d4dd00062e),
110
- created by members in the Bourne Group. Copyright © Bourne Group, used under the [MIT](https://opensource.org/license/mit) license.
114
+ created by members in the Bourne Group. Copyright © Bourne Group, used under the [MIT](https://opensource.org/license/mit) license.
@@ -0,0 +1,39 @@
1
+ pychemstation/__init__.py,sha256=SpTl-Tg1B1HTyjNOE-8ue-N2wGnXN_2zl7RFUSxlkiM,33
2
+ pychemstation/out.txt,sha256=PLwo0w7AOhwQUSmvf3jupRuBH9eEtPmVhLrVaFoDqJo,5990
3
+ pychemstation/tests.ipynb,sha256=rDrl2AyP47sWO5ZmPxUrMzExS8ex1k1NIe9UbMwkKio,41136
4
+ pychemstation/analysis/__init__.py,sha256=EWoU47iyn9xGS-b44zK9eq50bSjOV4AC5dvt420YMI4,44
5
+ pychemstation/analysis/base_spectrum.py,sha256=dPULGlr-sMHNMDIdyzlvX8taw_nkBliKTb00lNI8cwk,16517
6
+ pychemstation/analysis/process_report.py,sha256=wysKaA06UeK_9ba2SZc9maP4P-HQfZDMD9NNt21kWcY,11850
7
+ pychemstation/analysis/spec_utils.py,sha256=UOo9hJR3evJfmaohEEsyb7aq6X996ofuUfu-GKjiDi8,10201
8
+ pychemstation/analysis/utils.py,sha256=rgpTJTrpsiBANbtsfys9xj0sqlTe__3J0OSeoygaQTM,2081
9
+ pychemstation/control/README.md,sha256=7Q0rY014y7Qq8wfL7GSQG0l2P1PXfmgB0qZ2YkkE7n0,3350
10
+ pychemstation/control/__init__.py,sha256=4xTy8X-mkn_PPZKr7w9rnj1wZhtmTesbQptPhpYmKXs,64
11
+ pychemstation/control/hplc.py,sha256=E_QFMOqUabiqCO6Pu4lZYTsiWhdQULw4AqyKPwiQx90,12628
12
+ pychemstation/control/controllers/README.md,sha256=S5cd4NJmPjs6TUH98BtPJJhiS1Lu-mxLCNS786ogOrQ,32
13
+ pychemstation/control/controllers/__init__.py,sha256=LuFEsVGN5sXuHW_DG61DWBDJ_fU4dMls4bQJ5XNRaok,166
14
+ pychemstation/control/controllers/comm.py,sha256=fRCFh3Ye-HnoGaur69NRdkLHNtdlMoJjIOTqeJe1tAk,7720
15
+ pychemstation/control/controllers/devices/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
+ pychemstation/control/controllers/devices/device.py,sha256=d9SwasjXTXplkRK5eH3asrNPo3BBZmAz6CKBYAuKSIc,1249
17
+ pychemstation/control/controllers/devices/injector.py,sha256=ynPQtvMFt1iK0LQBf4ZEYdxJCyavmashXwyCQbmRjuw,5542
18
+ pychemstation/control/controllers/tables/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
+ pychemstation/control/controllers/tables/method.py,sha256=UMLwzsMYsZx53PMgmKIe6LcK4JjAUpuK41x9VMJObNw,17709
20
+ pychemstation/control/controllers/tables/ms.py,sha256=JFD-tOhu8uRyKdl-E3-neRssii8MNqVRIlsrnFhNY_M,682
21
+ pychemstation/control/controllers/tables/sequence.py,sha256=UT0KUDnn8A-19V24ZgW3KduSulvtbdvsJF9NJBUrz9M,13109
22
+ pychemstation/control/controllers/tables/table.py,sha256=L7OECX502lk2o88hu5Sdb3O4cJxsNGic2193oSz7urI,12298
23
+ pychemstation/generated/__init__.py,sha256=GAoZFAYbPVEJDkcOw3e1rgOqd7TCW0HyKNPM8OMehMg,1005
24
+ pychemstation/generated/dad_method.py,sha256=zfS9op450CRSGPKkUr9qUyPBbND06b9N8SUU9j4cosM,8408
25
+ pychemstation/generated/pump_method.py,sha256=c_FB14rgODZyH5eDb3kxZAI77xRj1HMpQkE2R6MypNA,12180
26
+ pychemstation/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
+ pychemstation/utils/chromatogram.py,sha256=s6mqru88E9YQGLbdr2Thm2plf8urCFoHHkMqW6_1Rz4,3338
28
+ pychemstation/utils/injector_types.py,sha256=hTgC-4xnO-EXOLOsCZ0L6TX4KUsB14Q-5jU4_hCzmfM,822
29
+ pychemstation/utils/macro.py,sha256=WgXGR8fgyR_QhRML9NUD3oZZBT4LLSI9uwuragHEe2k,2904
30
+ pychemstation/utils/method_types.py,sha256=5FK7RThLhaQcLrzRi_qLnlPqZuGPtwwipP6eMoq0kpE,1638
31
+ pychemstation/utils/parsing.py,sha256=bnFIsZZwFy9NKzVUf517yN-ogzQbm0hp_aho3KUD6Is,9317
32
+ pychemstation/utils/pump_types.py,sha256=HWQHxscGn19NTrfYBwQRCO2VcYfwyko7YfBO5uDhEm4,93
33
+ pychemstation/utils/sequence_types.py,sha256=x2EClcq6ROdzeLZg63XcXXTknwl2aZ48Vuyru0xZjgA,1086
34
+ pychemstation/utils/table_types.py,sha256=7txqW_oNpkh4venSkGEtreVe6UV9dzNB1DTrIeTkQHA,3217
35
+ pychemstation/utils/tray_types.py,sha256=eOO-muUjadyvCM8JnYAZVyxJeyYBlENP1zXiFskAFbs,5049
36
+ pychemstation-0.8.0.dist-info/METADATA,sha256=7cSMnoyDeOne85r2n7Bh3IsBeC5xWGVhuu4I0hNTeCo,4491
37
+ pychemstation-0.8.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
38
+ pychemstation-0.8.0.dist-info/licenses/LICENSE,sha256=9bdF75gIf1MecZ7oymqWgJREVz7McXPG-mjqrTmzzD8,18658
39
+ pychemstation-0.8.0.dist-info/RECORD,,
@@ -1,5 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.6.0)
2
+ Generator: hatchling 1.27.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
-
@@ -1,206 +0,0 @@
1
- """
2
- Module to provide API for the communication with Agilent HPLC systems.
3
-
4
- HPLCController sends commands to Chemstation software via a command file.
5
- Answers are received via reply file. On the Chemstation side, a custom
6
- Macro monitors the command file, executes commands and writes to the reply file.
7
- Each command is given a number (cmd_no) to keep track of which commands have
8
- been processed.
9
-
10
- Authors: Alexander Hammer, Hessam Mehr, Lucy Hao
11
- """
12
-
13
- import os
14
- import time
15
-
16
- from result import Result, Ok, Err
17
- from ..utils.macro import *
18
- from ..utils.method_types import *
19
-
20
-
21
- class CommunicationController:
22
- """
23
- Class that communicates with Agilent using Macros
24
- """
25
-
26
- # maximum command number
27
- MAX_CMD_NO = 255
28
-
29
- def __init__(
30
- self,
31
- comm_dir: str,
32
- cmd_file: str = "cmd",
33
- reply_file: str = "reply",
34
- ):
35
- """
36
- :param comm_dir:
37
- :param cmd_file: Name of command file
38
- :param reply_file: Name of reply file
39
- """
40
- if os.path.isdir(comm_dir):
41
- self.cmd_file = os.path.join(comm_dir, cmd_file)
42
- self.reply_file = os.path.join(comm_dir, reply_file)
43
- self.cmd_no = 0
44
- else:
45
- raise FileNotFoundError(f"comm_dir: {comm_dir} not found.")
46
- self._most_recent_hplc_status = None
47
-
48
- # Create files for Chemstation to communicate with Python
49
- open(self.cmd_file, "a").close()
50
- open(self.reply_file, "a").close()
51
-
52
- self.reset_cmd_counter()
53
-
54
- def get_num_val(self, cmd: str) -> Union[int, float, Err]:
55
- self.send(Command.GET_NUM_VAL_CMD.value.format(cmd=cmd))
56
- res = self.receive()
57
- if res.is_ok():
58
- return res.ok_value.num_response
59
- else:
60
- raise RuntimeError("Failed to get number.")
61
-
62
- def get_text_val(self, cmd: str) -> str:
63
- self.send(Command.GET_TEXT_VAL_CMD.value.format(cmd=cmd))
64
- res = self.receive()
65
- if res.is_ok():
66
- return res.ok_value.string_response
67
- else:
68
- raise RuntimeError("Failed to get string")
69
-
70
- def get_status(self) -> Union[HPLCRunningStatus, HPLCAvailStatus, HPLCErrorStatus]:
71
- """Get device status(es).
72
-
73
- :return: list of ChemStation's current status
74
- """
75
- self.send(Command.GET_STATUS_CMD)
76
- time.sleep(1)
77
-
78
- try:
79
- parsed_response = self.receive().value.string_response
80
- self._most_recent_hplc_status = str_to_status(parsed_response)
81
- return self._most_recent_hplc_status
82
- except IOError:
83
- return HPLCErrorStatus.NORESPONSE
84
- except IndexError:
85
- return HPLCErrorStatus.MALFORMED
86
-
87
- def set_status(self):
88
- """Updates current status of HPLC machine"""
89
- self._most_recent_hplc_status = self.get_status()
90
-
91
- def check_if_running(self) -> bool:
92
- """Checks if HPLC machine is in an available state, meaning a state that data is not being written.
93
-
94
- :return: whether the HPLC machine is in a safe state to retrieve data back."""
95
- self.set_status()
96
- hplc_avail = isinstance(self._most_recent_hplc_status, HPLCAvailStatus)
97
- time.sleep(30)
98
- self.set_status()
99
- hplc_actually_avail = isinstance(self._most_recent_hplc_status, HPLCAvailStatus)
100
- return hplc_avail and hplc_actually_avail
101
-
102
- def _send(self, cmd: str, cmd_no: int, num_attempts=5) -> None:
103
- """Low-level execution primitive. Sends a command string to HPLC.
104
-
105
- :param cmd: string to be sent to HPLC
106
- :param cmd_no: Command number
107
- :param num_attempts: Number of attempts to send the command before raising exception.
108
- :raises IOError: Could not write to command file.
109
- """
110
- err = None
111
- for _ in range(num_attempts):
112
- time.sleep(1)
113
- try:
114
- with open(self.cmd_file, "w", encoding="utf8") as cmd_file:
115
- cmd_file.write(f"{cmd_no} {cmd}")
116
- except IOError as e:
117
- err = e
118
- continue
119
- else:
120
- return
121
- else:
122
- raise IOError(f"Failed to send command #{cmd_no}: {cmd}.") from err
123
-
124
- def _receive(self, cmd_no: int, num_attempts=100) -> Result[str, str]:
125
- """Low-level execution primitive. Recives a response from HPLC.
126
-
127
- :param cmd_no: Command number
128
- :param num_attempts: Number of retries to open reply file
129
- :raises IOError: Could not read reply file.
130
- :return: Potential ChemStation response
131
- """
132
- err = None
133
- for _ in range(num_attempts):
134
- time.sleep(1)
135
-
136
- try:
137
- with open(self.reply_file, "r", encoding="utf_16") as reply_file:
138
- response = reply_file.read()
139
- except OSError as e:
140
- err = e
141
- continue
142
-
143
- try:
144
- first_line = response.splitlines()[0]
145
- response_no = int(first_line.split()[0])
146
- except IndexError as e:
147
- err = e
148
- continue
149
-
150
- # check that response corresponds to sent command
151
- if response_no == cmd_no:
152
- return Ok(response)
153
- else:
154
- continue
155
- else:
156
- return Err(f"Failed to receive reply to command #{cmd_no} due to {err}.")
157
-
158
- def sleepy_send(self, cmd: Union[Command, str]):
159
- self.send("Sleep 0.1")
160
- self.send(cmd)
161
- self.send("Sleep 0.1")
162
-
163
- def send(self, cmd: Union[Command, str]):
164
- """Sends a command to Chemstation.
165
-
166
- :param cmd: Command to be sent to HPLC
167
- """
168
- if self.cmd_no == self.MAX_CMD_NO:
169
- self.reset_cmd_counter()
170
-
171
- cmd_to_send: str = cmd.value if isinstance(cmd, Command) else cmd
172
- self.cmd_no += 1
173
- self._send(cmd_to_send, self.cmd_no)
174
- f = open("out.txt", "a")
175
- f.write(cmd_to_send + "\n")
176
- f.close()
177
-
178
- def receive(self) -> Result[Response, str]:
179
- """Returns messages received in reply file.
180
-
181
- :return: ChemStation response
182
- """
183
- num_response_prefix = "Numerical Responses:"
184
- str_response_prefix = "String Responses:"
185
- possible_response = self._receive(self.cmd_no)
186
- if Ok(possible_response):
187
- lines = possible_response.value.splitlines()
188
- for line in lines:
189
- if str_response_prefix in line and num_response_prefix in line:
190
- string_responses_dirty, _, numerical_responses = line.partition(num_response_prefix)
191
- _, _, string_responses = string_responses_dirty.partition(str_response_prefix)
192
- return Ok(Response(string_response=string_responses.strip(),
193
- num_response=float(numerical_responses.strip())))
194
- return Err(f"Could not retrieve HPLC response")
195
- else:
196
- return Err(f"Could not establish response to HPLC: {possible_response}")
197
-
198
- def reset_cmd_counter(self):
199
- """Resets the command counter."""
200
- self._send(Command.RESET_COUNTER_CMD.value, cmd_no=self.MAX_CMD_NO + 1)
201
- self._receive(cmd_no=self.MAX_CMD_NO + 1)
202
- self.cmd_no = 0
203
-
204
- def stop_macro(self):
205
- """Stops Macro execution. Connection will be lost."""
206
- self.send(Command.STOP_MACRO_CMD)
@@ -1,12 +0,0 @@
1
- from ....control.controllers import CommunicationController
2
- from .device import DeviceController
3
- from ....utils.table_types import Table
4
-
5
-
6
- class ColumnController(DeviceController):
7
-
8
- def __init__(self, controller: CommunicationController, table: Table):
9
- super().__init__(controller, table)
10
-
11
- def get_row(self, row: int):
12
- pass
File without changes
@@ -1,43 +0,0 @@
1
- from ....control.controllers import CommunicationController
2
- from .device import DeviceController
3
- from ....utils.pump_types import Pump
4
- from ....utils.table_types import Table
5
-
6
-
7
- class PumpController(DeviceController):
8
-
9
- def __init__(self, controller: CommunicationController, table: Table):
10
- super().__init__(controller, table)
11
- self.A1 = Pump(in_use=True, solvent="A1")
12
- self.B1 = Pump(in_use=True, solvent="B1")
13
- self.A2 = Pump(in_use=False, solvent="A2")
14
- self.B2 = Pump(in_use=False, solvent="B2")
15
-
16
- def validate_pumps(self):
17
- invalid_A_pump_usage = self.A1.in_use and self.A2.in_use
18
- invalid_B_pump_usage = self.B1.in_use and self.B2.in_use
19
- if invalid_A_pump_usage or invalid_B_pump_usage:
20
- raise AttributeError
21
-
22
- def switch_pump(self, num: int, pump: str):
23
- if pump == "A":
24
- if num == 1:
25
- self.A1.in_use = True
26
- self.A2.in_use = False
27
- elif num == 2:
28
- self.A1.in_use = False
29
- self.A2.in_use = True
30
- elif pump == "B":
31
- if num == 1:
32
- self.B1.in_use = True
33
- self.B2.in_use = False
34
- elif num == 2:
35
- self.B1.in_use = False
36
- self.B2.in_use = True
37
- self.purge()
38
-
39
- def purge(self):
40
- pass
41
-
42
- def get_row(self, row: int):
43
- pass