Skip to content

Commit 359a042

Browse files
refactor agilent gen5
1 parent 87ad6d9 commit 359a042

3 files changed

Lines changed: 403 additions & 176 deletions

File tree

src/allotropy/parsers/agilent_gen5/agilent_gen5_parser.py

Lines changed: 54 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -9,24 +9,26 @@
99
from allotropy.named_file_contents import NamedFileContents
1010
from allotropy.parsers.agilent_gen5.agilent_gen5_reader import AgilentGen5Reader
1111
from allotropy.parsers.agilent_gen5.agilent_gen5_structure import (
12-
create_kinetic_results,
1312
create_metadata,
14-
create_results,
15-
create_spectrum_results,
13+
Gen5DataContext,
1614
get_concentrations,
1715
get_identifiers,
1816
get_kinetic_measurements,
1917
get_results_section,
2018
get_temperature,
2119
HeaderData,
2220
KineticData,
21+
KineticResultProcessor,
2322
ReadData,
23+
ResultProcessor,
24+
SpectralResultProcessor,
25+
StandardResultProcessor,
2426
)
2527
from allotropy.parsers.agilent_gen5.constants import (
2628
NO_MEASUREMENTS_ERROR,
27-
ReadType,
2829
)
2930
from allotropy.parsers.release_state import ReleaseState
31+
from allotropy.parsers.utils.timestamp_parser import TimestampParser
3032
from allotropy.parsers.vendor_parser import VendorParser
3133

3234

@@ -36,85 +38,66 @@ class AgilentGen5Parser(VendorParser[Data, Model]):
3638
SUPPORTED_EXTENSIONS = AgilentGen5Reader.SUPPORTED_EXTENSIONS
3739
SCHEMA_MAPPER = Mapper
3840

41+
def __init__(self, timestamp_parser: TimestampParser | None = None):
42+
super().__init__(timestamp_parser)
43+
self._processors = [
44+
SpectralResultProcessor(),
45+
KineticResultProcessor(),
46+
StandardResultProcessor(),
47+
]
48+
3949
def create_data(self, named_file_contents: NamedFileContents) -> Data:
4050
reader = AgilentGen5Reader(named_file_contents)
51+
context = self._extract_data_context(
52+
reader, named_file_contents.original_file_path
53+
)
4154

42-
if (results_section := get_results_section(reader)) is None:
43-
reader.header_data.get_unread()
55+
processor = self._get_processor(context)
56+
measurement_groups, calculated_data = processor.process(context)
57+
58+
if not measurement_groups:
4459
raise AllotropeConversionError(NO_MEASUREMENTS_ERROR)
4560

46-
header_data = HeaderData.create(
47-
reader.header_data, named_file_contents.original_file_path
61+
return Data(
62+
metadata=create_metadata(context.header_data),
63+
measurement_groups=measurement_groups,
64+
calculated_data=calculated_data,
4865
)
49-
read_data = ReadData.create(reader.sections["Procedure Details"])
50-
kinetic_data = KineticData.create(reader.sections["Procedure Details"])
5166

52-
sample_identifiers = get_identifiers(reader.sections.get("Layout"))
53-
concentration_values = get_concentrations(reader.sections.get("Layout"))
54-
actual_temperature = get_temperature(reader.sections.get("Actual Temperature"))
55-
kinetic_result = get_kinetic_measurements(reader.sections.get("Time"))
67+
def _extract_data_context(
68+
self, reader: AgilentGen5Reader, file_path: str
69+
) -> Gen5DataContext:
70+
results_section = get_results_section(reader)
71+
if not results_section:
72+
reader.header_data.get_unread()
73+
raise AllotropeConversionError(NO_MEASUREMENTS_ERROR)
74+
75+
kinetic_result = get_kinetic_measurements(reader.time_section)
5676
kinetic_measurements, kinetic_elapsed_time, kinetic_errors = kinetic_result or (
5777
{},
5878
[],
5979
{},
6080
)
6181

62-
if kinetic_data and not (kinetic_measurements and kinetic_elapsed_time):
63-
msg = "Kinetic data is present in the file but no kinetic measurements data is found."
64-
raise AllotropeConversionError(msg)
65-
66-
read_is_spectral = read_data[0].read_type == ReadType.SPECTRUM
67-
if read_is_spectral and reader.sections.get("Wavelength"):
68-
(
69-
wavelength_measurements,
70-
wavelength_calculated_data,
71-
) = create_spectrum_results(
72-
header_data,
73-
read_data_list=read_data,
74-
wavelengths_sections=reader.sections.get("Wavelength"),
75-
sample_identifiers=sample_identifiers,
76-
actual_temperature=actual_temperature,
77-
results_section=results_section,
78-
concentration_values=concentration_values,
79-
)
80-
81-
if not wavelength_measurements:
82-
raise AllotropeConversionError(NO_MEASUREMENTS_ERROR)
83-
84-
return Data(
85-
metadata=create_metadata(header_data),
86-
measurement_groups=wavelength_measurements,
87-
calculated_data=wavelength_calculated_data,
88-
)
82+
return Gen5DataContext(
83+
header_data=HeaderData.create(reader.header_data, file_path),
84+
read_data=ReadData.create(reader.procedure_details),
85+
kinetic_data=KineticData.create(reader.procedure_details),
86+
results_section=results_section,
87+
sample_identifiers=get_identifiers(reader.layout_section),
88+
concentration_values=get_concentrations(reader.layout_section),
89+
actual_temperature=get_temperature(reader.actual_temperature_section),
90+
kinetic_measurements=kinetic_measurements,
91+
kinetic_elapsed_time=kinetic_elapsed_time,
92+
kinetic_errors=kinetic_errors,
93+
wavelength_section=reader.wavelength_section,
94+
)
8995

90-
if kinetic_data:
91-
measurement_groups, calculated_data = create_kinetic_results(
92-
results_section,
93-
header_data,
94-
read_data,
95-
sample_identifiers,
96-
actual_temperature,
97-
kinetic_data,
98-
kinetic_measurements,
99-
kinetic_elapsed_time,
100-
kinetic_errors,
101-
concentration_values,
102-
)
103-
else:
104-
measurement_groups, calculated_data = create_results(
105-
results_section,
106-
header_data,
107-
read_data,
108-
sample_identifiers,
109-
actual_temperature,
110-
concentration_values,
111-
)
96+
def _get_processor(self, context: Gen5DataContext) -> ResultProcessor:
97+
"""Get the appropriate processor for the given context."""
98+
for processor in self._processors:
99+
if processor.can_process(context):
100+
return processor
112101

113-
if not measurement_groups:
114-
raise AllotropeConversionError(NO_MEASUREMENTS_ERROR)
115-
116-
return Data(
117-
metadata=create_metadata(header_data),
118-
measurement_groups=measurement_groups,
119-
calculated_data=calculated_data,
120-
)
102+
msg = "No suitable processor found for the data."
103+
raise AllotropeConversionError(msg)

src/allotropy/parsers/agilent_gen5/agilent_gen5_reader.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,31 @@ def __init__(self, named_file_contents: NamedFileContents) -> None:
5959
lines = list(plate_reader.pop_until_empty())
6060
self.sections[lines[0].split("\t")[0].strip(":")] = lines
6161
plate_reader.drop_empty()
62+
63+
def get_required_section(self, section_name: str) -> list[str]:
64+
"""Get a required section, raises error if not found."""
65+
section = self.sections.get(section_name)
66+
if section is None:
67+
msg = f"Required section '{section_name}' not found."
68+
raise AllotropeConversionError(msg)
69+
return section
70+
71+
@property
72+
def procedure_details(self) -> list[str]:
73+
return self.get_required_section("Procedure Details")
74+
75+
@property
76+
def layout_section(self) -> list[str] | None:
77+
return self.sections.get("Layout")
78+
79+
@property
80+
def wavelength_section(self) -> list[str] | None:
81+
return self.sections.get("Wavelength")
82+
83+
@property
84+
def time_section(self) -> list[str] | None:
85+
return self.sections.get("Time")
86+
87+
@property
88+
def actual_temperature_section(self) -> list[str] | None:
89+
return self.sections.get("Actual Temperature")

0 commit comments

Comments
 (0)