pychemstation 0.8.3__py3-none-any.whl → 0.9.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 (33) hide show
  1. pychemstation/__init__.py +1 -1
  2. pychemstation/analysis/__init__.py +4 -1
  3. pychemstation/analysis/base_spectrum.py +4 -4
  4. pychemstation/{utils → analysis}/chromatogram.py +4 -7
  5. pychemstation/analysis/process_report.py +121 -74
  6. pychemstation/control/README.md +22 -46
  7. pychemstation/control/__init__.py +5 -0
  8. pychemstation/control/controllers/__init__.py +2 -0
  9. pychemstation/control/controllers/comm.py +39 -18
  10. pychemstation/control/controllers/devices/device.py +27 -14
  11. pychemstation/control/controllers/devices/injector.py +33 -89
  12. pychemstation/control/controllers/tables/method.py +266 -111
  13. pychemstation/control/controllers/tables/ms.py +7 -4
  14. pychemstation/control/controllers/tables/sequence.py +171 -82
  15. pychemstation/control/controllers/tables/table.py +192 -116
  16. pychemstation/control/hplc.py +117 -83
  17. pychemstation/generated/__init__.py +0 -2
  18. pychemstation/generated/dad_method.py +1 -1
  19. pychemstation/generated/pump_method.py +15 -19
  20. pychemstation/utils/injector_types.py +1 -1
  21. pychemstation/utils/macro.py +12 -11
  22. pychemstation/utils/method_types.py +3 -2
  23. pychemstation/{analysis/utils.py → utils/num_utils.py} +2 -2
  24. pychemstation/utils/parsing.py +1 -11
  25. pychemstation/utils/sequence_types.py +4 -5
  26. pychemstation/{analysis → utils}/spec_utils.py +1 -2
  27. pychemstation/utils/table_types.py +10 -9
  28. pychemstation/utils/tray_types.py +48 -38
  29. {pychemstation-0.8.3.dist-info → pychemstation-0.9.0.dist-info}/METADATA +63 -24
  30. pychemstation-0.9.0.dist-info/RECORD +37 -0
  31. pychemstation-0.8.3.dist-info/RECORD +0 -37
  32. {pychemstation-0.8.3.dist-info → pychemstation-0.9.0.dist-info}/WHEEL +0 -0
  33. {pychemstation-0.8.3.dist-info → pychemstation-0.9.0.dist-info}/licenses/LICENSE +0 -0
@@ -4,47 +4,47 @@ Module to provide API for higher-level HPLC actions.
4
4
  Authors: Lucy Hao
5
5
  """
6
6
 
7
- from typing import Union, Optional, List, Tuple
7
+ from __future__ import annotations
8
8
 
9
- from .controllers.devices.injector import InjectorController
10
- from ..analysis.process_report import ReportType, AgilentReport
11
- from ..control.controllers import MethodController, SequenceController, CommunicationController
12
- from ..utils.chromatogram import AgilentChannelChromatogramData
13
- from ..utils.injector_types import InjectorTable
9
+ from typing import Dict, List, Optional, Tuple, Union
10
+
11
+ from pychemstation.analysis.chromatogram import (
12
+ AgilentHPLCChromatogram,
13
+ )
14
+
15
+ from ..analysis.process_report import AgilentReport, ReportType
16
+ from ..control.controllers import (
17
+ CommunicationController,
18
+ MethodController,
19
+ SequenceController,
20
+ )
21
+ from pychemstation.analysis.chromatogram import AgilentChannelChromatogramData
14
22
  from ..utils.macro import Command, Response, Status
15
23
  from ..utils.method_types import MethodDetails
16
24
  from ..utils.sequence_types import SequenceTable
17
25
  from ..utils.table_types import Table
26
+ from .controllers.devices.injector import InjectorController
18
27
 
19
28
 
20
29
  class HPLCController:
21
30
  # tables
22
- METHOD_TIMETABLE = Table(
23
- register="RCPMP1Method[1]",
24
- name="Timetable"
25
- )
26
-
27
- SEQUENCE_TABLE = Table(
28
- register="_sequence[1]",
29
- name="SeqTable1"
30
- )
31
-
32
- INJECTOR_TABLE = Table(
33
- register="RCWLS1Pretreatment[1]",
34
- name="InstructionTable"
35
- )
36
-
37
- MSD_TABLE = Table(
38
- register="MSACQINFO[1]",
39
- name="SprayChamber"
40
- )
41
-
42
- def __init__(self,
43
- comm_dir: str,
44
- method_dir: str,
45
- sequence_dir: str,
46
- data_dirs: List[str],
47
- offline: bool = False):
31
+ METHOD_TIMETABLE = Table(register="RCPMP1Method[1]", name="Timetable")
32
+
33
+ SEQUENCE_TABLE = Table(register="_sequence[1]", name="SeqTable1")
34
+
35
+ INJECTOR_TABLE = Table(register="RCWLS1Pretreatment[1]", name="InstructionTable")
36
+
37
+ MSD_TABLE = Table(register="MSACQINFO[1]", name="SprayChamber")
38
+
39
+ def __init__(
40
+ self,
41
+ comm_dir: str,
42
+ method_dir: str,
43
+ sequence_dir: str,
44
+ data_dirs: List[str],
45
+ offline: bool = False,
46
+ debug: bool = False,
47
+ ):
48
48
  """Initialize HPLC controller. The `hplc_talk.mac` macro file must be loaded in the Chemstation software.
49
49
  `comm_dir` must match the file path in the macro file. All file paths are normal strings, with the left slash
50
50
  double escaped: "C:\\my_folder\\"
@@ -56,21 +56,29 @@ class HPLCController:
56
56
  :param sequence_dir: Name of directory where sequence files are stored.
57
57
  :raises FileNotFoundError: If either `data_dir`, `method_dir`, `sequence_dir`, `sequence_data_dir`or `comm_dir` is not a valid directory.
58
58
  """
59
- self.comm = CommunicationController(comm_dir=comm_dir) if not offline else None
60
- self.method_controller = MethodController(controller=self.comm,
61
- src=method_dir,
62
- data_dirs=data_dirs,
63
- table=self.METHOD_TIMETABLE,
64
- offline=offline,
65
- injector_controller=InjectorController(controller=self.comm,
66
- table=self.INJECTOR_TABLE,
67
- offline=offline))
68
- self.sequence_controller = SequenceController(controller=self.comm,
69
- src=sequence_dir,
70
- data_dirs=data_dirs,
71
- table=self.SEQUENCE_TABLE,
72
- method_controller=self.method_controller,
73
- offline=offline)
59
+ self.comm = (
60
+ CommunicationController(comm_dir=comm_dir, debug=debug)
61
+ if not offline
62
+ else None
63
+ )
64
+ self.method_controller = MethodController(
65
+ controller=self.comm,
66
+ src=method_dir,
67
+ data_dirs=data_dirs,
68
+ table=self.METHOD_TIMETABLE,
69
+ offline=offline,
70
+ injector_controller=InjectorController(
71
+ controller=self.comm, table=self.INJECTOR_TABLE, offline=offline
72
+ ),
73
+ )
74
+ self.sequence_controller = SequenceController(
75
+ controller=self.comm,
76
+ src=sequence_dir,
77
+ data_dirs=data_dirs,
78
+ table=self.SEQUENCE_TABLE,
79
+ method_controller=self.method_controller,
80
+ offline=offline,
81
+ )
74
82
 
75
83
  def send(self, cmd: Union[Command, str]):
76
84
  """
@@ -80,29 +88,32 @@ class HPLCController:
80
88
  """
81
89
  if not self.comm:
82
90
  raise RuntimeError(
83
- "Communication controller must be initialized before sending command. It is currently in offline mode.")
91
+ "Communication controller must be initialized before sending command. It is currently in offline mode."
92
+ )
84
93
  self.comm.send(cmd)
85
94
 
86
95
  def receive(self) -> Response:
87
96
  """
88
97
  Get the most recent response from Chemstation.
89
98
 
90
- :returns: most recent response from a macro that returned a response.
99
+ :return: most recent response from a macro that returned a response.
91
100
  """
92
101
  if not self.comm:
93
102
  raise RuntimeError(
94
- "Communication controller must be initialized before sending command. It is currently in offline mode.")
103
+ "Communication controller must be initialized before sending command. It is currently in offline mode."
104
+ )
95
105
  return self.comm.receive().value
96
106
 
97
107
  def status(self) -> Status:
98
108
  """
99
109
  Get the current status of the HPLC machine.
100
110
 
101
- :returns: current status of the HPLC machine; Status types can be found in `pychemstation.utils.macro`
111
+ :return: current status of the HPLC machine; Status types can be found in `pychemstation.utils.macro`
102
112
  """
103
113
  if not self.comm:
104
114
  raise RuntimeError(
105
- "Communication controller must be initialized before sending command. It is currently in offline mode.")
115
+ "Communication controller must be initialized before sending command. It is currently in offline mode."
116
+ )
106
117
  return self.comm.get_status()
107
118
 
108
119
  def switch_method(self, method_name: str):
@@ -126,7 +137,12 @@ class HPLCController:
126
137
  """
127
138
  self.sequence_controller.switch(sequence_name)
128
139
 
129
- def run_method(self, experiment_name: str, add_timestamp: bool = True, stall_while_running: bool = True):
140
+ def run_method(
141
+ self,
142
+ experiment_name: str,
143
+ add_timestamp: bool = True,
144
+ stall_while_running: bool = True,
145
+ ):
130
146
  """
131
147
  This is the preferred method to trigger a run.
132
148
  Starts the currently selected method, storing data
@@ -137,9 +153,11 @@ class HPLCController:
137
153
  :param stall_while_running: whether to return or stall while HPLC runs.
138
154
  :param add_timestamp: whether to append a timestamp in '%Y-%m-%d-%H-%M' format to end of experiment name.
139
155
  """
140
- self.method_controller.run(experiment_name=experiment_name,
141
- stall_while_running=stall_while_running,
142
- add_timestamp=add_timestamp)
156
+ self.method_controller.run(
157
+ experiment_name=experiment_name,
158
+ stall_while_running=stall_while_running,
159
+ add_timestamp=add_timestamp,
160
+ )
143
161
 
144
162
  def stop_method(self):
145
163
  """Stops the current running method, manual intervention may be needed."""
@@ -159,7 +177,7 @@ class HPLCController:
159
177
  """
160
178
  Check if the currently running method (if any) is done.
161
179
 
162
- :returns: the percent of the method run completed, and whether the run is complete.
180
+ :returns the percent of the method run completed, and whether the run is complete.
163
181
  """
164
182
  return self.method_controller.check_hplc_run_finished()
165
183
 
@@ -167,7 +185,7 @@ class HPLCController:
167
185
  """
168
186
  Check if the currently running sequence (if any) is done.
169
187
 
170
- :returns: the percent of the sequence run completed, and whether the run is complete.
188
+ :return: the percent of the sequence run completed, and whether the run is complete.
171
189
  """
172
190
  return self.sequence_controller.check_hplc_run_finished()
173
191
 
@@ -188,47 +206,67 @@ class HPLCController:
188
206
  """
189
207
  self.sequence_controller.edit(updated_sequence)
190
208
 
191
- def get_last_run_method_report(self,
192
- custom_path: Optional[str] = None,
193
- report_type: ReportType = ReportType.CSV) -> AgilentReport:
209
+ def get_last_run_method_report(
210
+ self,
211
+ custom_path: Optional[str] = None,
212
+ report_type: ReportType = ReportType.CSV,
213
+ ) -> AgilentReport:
194
214
  """
195
215
  Return data contained in the REPORT files. Use `aghplctools` if you want more report processing utility.
216
+
196
217
  :param custom_path: path to sequence folder
197
218
  :param report_type: read either the TXT or CSV version
198
- :returns: report data for method
219
+ :return: report data for method
199
220
  """
200
- return self.method_controller.get_report(custom_path=custom_path, report_type=report_type)[0]
221
+ return self.method_controller.get_report(
222
+ custom_path=custom_path, report_type=report_type
223
+ )[0]
201
224
 
202
- def get_last_run_method_data(self, read_uv: bool = False,
203
- data: Optional[str] = None) -> AgilentChannelChromatogramData:
225
+ def get_last_run_method_data(
226
+ self, read_uv: bool = False, custom_path: Optional[str] = None
227
+ ) -> Dict[str, AgilentHPLCChromatogram] | AgilentChannelChromatogramData:
204
228
  """
205
229
  Returns the last run method data.
206
230
 
207
- :param data: If you want to just load method data but from a file path. This file path must be the complete file path.
231
+ :param custom_path: If you want to just load method data but from a file path. This file path must be the complete file path.
208
232
  :param read_uv: whether to also read the UV file
209
233
  """
210
- return self.method_controller.get_data(custom_path=data, read_uv=read_uv)
211
-
212
- def get_last_run_sequence_reports(self,
213
- custom_path: Optional[str] = None,
214
- report_type: ReportType = ReportType.CSV) -> List[AgilentReport]:
234
+ if read_uv:
235
+ return self.method_controller.get_data_uv(custom_path=custom_path)
236
+ else:
237
+ return self.method_controller.get_data(custom_path=custom_path)
238
+
239
+ def get_last_run_sequence_reports(
240
+ self,
241
+ custom_path: Optional[str] = None,
242
+ report_type: ReportType = ReportType.CSV,
243
+ ) -> List[AgilentReport]:
215
244
  """
216
245
  Return data contained in the REPORT files. Use `aghplctools` if you want more report processing utility.
246
+
217
247
  :param custom_path: path to sequence folder
218
248
  :param report_type: read either the TXT or CSV version
219
- :returns: list of reports for each row
249
+ :return: list of reports for each row
220
250
  """
221
- return self.sequence_controller.get_report(custom_path=custom_path, report_type=report_type)
222
-
223
- def get_last_run_sequence_data(self, read_uv: bool = False,
224
- data: Optional[str] = None) -> List[AgilentChannelChromatogramData]:
251
+ return self.sequence_controller.get_report(
252
+ custom_path=custom_path, report_type=report_type
253
+ )
254
+
255
+ def get_last_run_sequence_data(
256
+ self, read_uv: bool = False, custom_path: Optional[str] = None
257
+ ) -> (
258
+ List[Dict[int, AgilentHPLCChromatogram]] | List[AgilentChannelChromatogramData]
259
+ ):
225
260
  """
226
261
  Returns data for all rows in the last run sequence data.
227
262
 
228
- :param data: If you want to just load sequence data but from a file path. This file path must be the complete file path.
263
+ :param custom_path: If you want to just load sequence data but from a file path. This file path must be the complete file path.
229
264
  :param read_uv: whether to also read the UV file
230
265
  """
231
- return self.sequence_controller.get_data(custom_path=data, read_uv=read_uv)
266
+ if read_uv:
267
+ return self.sequence_controller.get_data_uv(custom_path=custom_path)
268
+ else:
269
+ return self.sequence_controller.get_data(custom_path=custom_path)
232
270
 
233
271
  def check_loaded_sequence(self) -> str:
234
272
  """Returns the name of the currently loaded sequence."""
@@ -238,10 +276,6 @@ class HPLCController:
238
276
  """Returns the name of the currently loaded method."""
239
277
  return self.method_controller.check()
240
278
 
241
- def load_injector_program(self) -> InjectorTable:
242
- """Returns all details of the injector program for the currently loaded method."""
243
- return self.method_controller.injector_controller.load()
244
-
245
279
  def load_method(self) -> MethodDetails:
246
280
  """Returns details of the currently loaded method, such as its starting modifier conditions and timetable."""
247
281
  return self.method_controller.load()
@@ -255,7 +289,7 @@ class HPLCController:
255
289
  self.send(Command.STANDBY_CMD)
256
290
 
257
291
  def preprun(self):
258
- """ Prepares all modules for run. All lamps and pumps are switched on."""
292
+ """Prepares all modules for run. All lamps and pumps are switched on."""
259
293
  self.send(Command.PREPRUN_CMD)
260
294
 
261
295
  def lamp_on(self):
@@ -19,13 +19,11 @@ from .dad_method import (
19
19
  AnalogOutput1,
20
20
  AnalogOutput2,
21
21
  DadMethod,
22
- PostTime,
23
22
  PrepareAutomation,
24
23
  PrepareMode,
25
24
  Signal,
26
25
  Signals,
27
26
  SpectraAcquisition,
28
- StopTime,
29
27
  )
30
28
 
31
29
  __all__ = [
@@ -1,5 +1,5 @@
1
1
  from dataclasses import dataclass, field
2
- from typing import Optional, List
2
+ from typing import List, Optional
3
3
 
4
4
 
5
5
  @dataclass
@@ -1,5 +1,5 @@
1
1
  from dataclasses import dataclass, field
2
- from typing import Optional, List
2
+ from typing import List, Optional
3
3
  from xml.etree.ElementTree import QName
4
4
 
5
5
 
@@ -313,25 +313,21 @@ class SolventElement:
313
313
  "required": True,
314
314
  },
315
315
  )
316
- channel1_extended_solvent_type: Optional[Channel1ExtendedSolventType] = (
317
- field(
318
- default=None,
319
- metadata={
320
- "name": "Channel1ExtendedSolventType",
321
- "type": "Element",
322
- "required": True,
323
- },
324
- )
316
+ channel1_extended_solvent_type: Optional[Channel1ExtendedSolventType] = field(
317
+ default=None,
318
+ metadata={
319
+ "name": "Channel1ExtendedSolventType",
320
+ "type": "Element",
321
+ "required": True,
322
+ },
325
323
  )
326
- channel2_extended_solvent_type: Optional[Channel2ExtendedSolventType] = (
327
- field(
328
- default=None,
329
- metadata={
330
- "name": "Channel2ExtendedSolventType",
331
- "type": "Element",
332
- "required": True,
333
- },
334
- )
324
+ channel2_extended_solvent_type: Optional[Channel2ExtendedSolventType] = field(
325
+ default=None,
326
+ metadata={
327
+ "name": "Channel2ExtendedSolventType",
328
+ "type": "Element",
329
+ "required": True,
330
+ },
335
331
  )
336
332
 
337
333
 
@@ -1,6 +1,6 @@
1
1
  from dataclasses import dataclass
2
2
  from enum import Enum
3
- from typing import Union, Optional, List
3
+ from typing import List, Optional, Union
4
4
 
5
5
  from pychemstation.utils.tray_types import Tray
6
6
 
@@ -1,8 +1,8 @@
1
1
  from __future__ import annotations
2
2
 
3
- from enum import Enum
4
- from typing import Union
5
3
  from dataclasses import dataclass
4
+ from enum import Enum
5
+ from typing import Union, Any, Type
6
6
 
7
7
 
8
8
  @dataclass
@@ -15,7 +15,7 @@ class Response:
15
15
  # See https://www.agilent.com/cs/library/usermanuals/Public/MACROS.PDF
16
16
  class Command(Enum):
17
17
  def __str__(self):
18
- return '%s' % self.value
18
+ return "%s" % self.value
19
19
 
20
20
  GET_NUM_VAL_CMD = "response_num = {cmd}"
21
21
  GET_TEXT_VAL_CMD = "response$ = {cmd}"
@@ -37,17 +37,17 @@ class Command(Enum):
37
37
  # Method and Sequence Related
38
38
  GET_METHOD_CMD = "response$ = _MethFile$"
39
39
  GET_ROWS_CMD = 'response_num = TabHdrVal({register}, "{table_name}", "{col_name}")'
40
- SWITCH_METHOD_CMD = 'LoadMethod _MethPath$, _MethFile$'
40
+ SWITCH_METHOD_CMD = "LoadMethod _MethPath$, _MethFile$"
41
41
  SWITCH_METHOD_CMD_SPECIFIC = 'LoadMethod "{method_dir}", "{method_name}.M"'
42
42
  START_METHOD_CMD = "StartMethod"
43
43
  RUN_METHOD_CMD = 'RunMethod "{data_dir}",, "{experiment_name}"'
44
44
  STOP_METHOD_CMD = "StopMethod"
45
- UPDATE_METHOD_CMD = 'UpdateMethod'
46
- SWITCH_SEQUENCE_CMD = 'LoadSequence _SeqPath$, _SeqFile$'
47
- SAVE_SEQUENCE_CMD = 'SaveSequence _SeqPath$, _SeqFile$'
45
+ UPDATE_METHOD_CMD = "UpdateMethod"
46
+ SWITCH_SEQUENCE_CMD = "LoadSequence _SeqPath$, _SeqFile$"
47
+ SAVE_SEQUENCE_CMD = "SaveSequence _SeqPath$, _SeqFile$"
48
48
  SAVE_METHOD_CMD = 'SaveMethod _MethPath$, _MethFile$, "{commit_msg}"'
49
- GET_SEQUENCE_CMD = 'response$ = _SeqFile$'
50
- RUN_SEQUENCE_CMD = 'RunSequence'
49
+ GET_SEQUENCE_CMD = "response$ = _SeqFile$"
50
+ RUN_SEQUENCE_CMD = "RunSequence"
51
51
 
52
52
 
53
53
  class HPLCRunningStatus(Enum):
@@ -76,7 +76,6 @@ class HPLCAvailStatus(Enum):
76
76
 
77
77
 
78
78
  class HPLCErrorStatus(Enum):
79
-
80
79
  @classmethod
81
80
  def has_member_key(cls, key):
82
81
  return key in cls.__members__
@@ -87,7 +86,9 @@ class HPLCErrorStatus(Enum):
87
86
  MALFORMED = "MALFORMED"
88
87
 
89
88
 
90
- def str_to_status(status: str) -> Union[HPLCAvailStatus, HPLCErrorStatus, HPLCRunningStatus]:
89
+ def str_to_status(
90
+ status: str,
91
+ ) -> Type[HPLCRunningStatus[Any] | HPLCErrorStatus[Any] | HPLCAvailStatus[Any]]:
91
92
  if HPLCErrorStatus.has_member_key(status):
92
93
  return HPLCErrorStatus[status]
93
94
  if HPLCRunningStatus.has_member_key(status):
@@ -2,11 +2,11 @@ from __future__ import annotations
2
2
 
3
3
  from dataclasses import dataclass
4
4
  from enum import Enum
5
- from typing import Union, Any, Optional
5
+ from typing import Any, Optional, Union
6
6
 
7
+ from ..generated import Signal
7
8
  from .injector_types import InjectorTable
8
9
  from .table_types import RegisterFlag
9
- from ..generated import Signal
10
10
 
11
11
 
12
12
  class PType(Enum):
@@ -47,6 +47,7 @@ class MethodDetails:
47
47
  :attribute params: the organic modifier (pump B) and flow rate displayed for the method (the time 0 settings)
48
48
  :attribute dad_wavelengthes:
49
49
  """
50
+
50
51
  name: str
51
52
  params: HPLCMethodParams
52
53
  timetable: list[TimeTableEntry]
@@ -11,7 +11,7 @@ def find_nearest_value_index(array, value) -> Tuple[float, int]:
11
11
  :param value: Target value.
12
12
  :type value: float
13
13
 
14
- :returns: Nearest value in array and its index.
14
+ :return: Nearest value in array and its index.
15
15
  """
16
16
 
17
17
  index_ = np.argmin(np.abs(array - value))
@@ -34,7 +34,7 @@ def interpolate_to_index(array, ids, precision: int = 100) -> np.array:
34
34
  :type ids: np.array[float]
35
35
  :param precision: Desired presion.
36
36
 
37
- :returns: New array with interpolated values according to provided indexes "ids".
37
+ :return: New array with interpolated values according to provided indexes "ids".
38
38
 
39
39
  Example:
40
40
  >>> interpolate_to_index(np.array([1.5]), np.array([1,2,3], 100))
@@ -13,6 +13,7 @@ I use it for file with version 130, genereted by an Agilent LC.
13
13
 
14
14
  import struct
15
15
  from struct import unpack
16
+
16
17
  import numpy as np
17
18
 
18
19
  # Constants used for binary file parsing
@@ -26,7 +27,6 @@ UINT32 = ENDIAN + "I"
26
27
 
27
28
 
28
29
  def fread(fid, nelements, dtype):
29
-
30
30
  """Equivalent to Matlab fread function"""
31
31
 
32
32
  if dtype is str:
@@ -41,7 +41,6 @@ def fread(fid, nelements, dtype):
41
41
 
42
42
 
43
43
  def parse_utf16_string(file_, encoding="UTF16"):
44
-
45
44
  """Parse a pascal type UTF16 encoded string from a binary file object"""
46
45
 
47
46
  # First read the expected number of CHARACTERS
@@ -52,7 +51,6 @@ def parse_utf16_string(file_, encoding="UTF16"):
52
51
 
53
52
 
54
53
  class cached_property(object):
55
-
56
54
  """A property that is only computed once per instance and then replaces
57
55
  itself with an ordinary attribute. Deleting the attribute resets the
58
56
  property.
@@ -72,7 +70,6 @@ class cached_property(object):
72
70
 
73
71
 
74
72
  class CHFile(object):
75
-
76
73
  """Class that implementats the Agilent .ch file format version
77
74
  130. Warning: Not all aspects of the file header is understood,
78
75
  so there may and probably is information that is not parsed. See
@@ -121,7 +118,6 @@ class CHFile(object):
121
118
  supported_versions = {130}
122
119
 
123
120
  def __init__(self, filepath):
124
-
125
121
  self.filepath = filepath
126
122
  self.metadata = {}
127
123
  with open(self.filepath, "rb") as file_:
@@ -129,7 +125,6 @@ class CHFile(object):
129
125
  self.values = self._parse_data(file_)
130
126
 
131
127
  def _parse_header(self, file_):
132
-
133
128
  """Parse the header"""
134
129
 
135
130
  # Parse and check version
@@ -153,7 +148,6 @@ class CHFile(object):
153
148
  ]
154
149
 
155
150
  def _parse_header_status(self):
156
-
157
151
  """Print known and unknown parts of the header"""
158
152
 
159
153
  file_ = open(self.filepath, "rb")
@@ -233,7 +227,6 @@ class CHFile(object):
233
227
  file_.close()
234
228
 
235
229
  def _parse_data(self, file_):
236
-
237
230
  """Parse the data. Decompress the delta-encoded data, and scale them
238
231
  with y-scaling"""
239
232
 
@@ -251,7 +244,6 @@ class CHFile(object):
251
244
  buff = [0, 0, 0, 0]
252
245
 
253
246
  while file_.tell() < stop:
254
-
255
247
  buff[0] = fread(file_, 1, INT16)[0][0]
256
248
  buff[1] = buff[3]
257
249
 
@@ -259,7 +251,6 @@ class CHFile(object):
259
251
  break
260
252
 
261
253
  for i in range(buff[0] & 4095):
262
-
263
254
  buff[2] = fread(file_, 1, INT16)[0][0]
264
255
 
265
256
  if buff[2] != -32768:
@@ -278,7 +269,6 @@ class CHFile(object):
278
269
 
279
270
  @cached_property
280
271
  def times(self):
281
-
282
272
  """The time values (x-value) for the data set in minutes"""
283
273
 
284
274
  return np.linspace(
@@ -1,17 +1,16 @@
1
1
  from __future__ import annotations
2
2
 
3
- from dataclasses import dataclass
4
3
  from enum import Enum
5
- from typing import Optional, Union
6
-
7
- from pychemstation.utils.tray_types import TenVialColumn, Tray
4
+ from typing import Optional, List
5
+ from dataclasses import dataclass, field
6
+ from pychemstation.utils.tray_types import Tray
8
7
 
9
8
 
10
9
  @dataclass
11
10
  class SequenceDataFiles:
12
11
  sequence_name: str
13
12
  dir: str
14
- child_dirs: Optional[list[str]] = None
13
+ child_dirs: List[str] = field(default_factory=list)
15
14
 
16
15
 
17
16
  class SampleType(Enum):
@@ -6,7 +6,7 @@ analysis.
6
6
  import numpy as np
7
7
  import scipy
8
8
 
9
- from .utils import find_nearest_value_index
9
+ from ..utils.num_utils import find_nearest_value_index
10
10
 
11
11
 
12
12
  def create_binary_peak_map(data):
@@ -28,7 +28,6 @@ def create_binary_peak_map(data):
28
28
  peak_map = np.full_like(data_c, False, dtype=bool)
29
29
 
30
30
  for _ in range(100500): # shouldn't take more iterations
31
-
32
31
  # looking for peaks
33
32
  peaks_found = np.logical_or(
34
33
  data_c > np.mean(data_c) + np.std(data_c) * 3,