Skip to content

Commit fa55d5d

Browse files
feat: Migrate example_weyland_yutani to REC/2025/03 plate reader schema (#1177)
## Summary - Migrate `example_weyland_yutani` tutorial parser from BENCHLING/2023/09 to REC/2025/03 plate reader schema mapper - First step in upgrading plate reader parsers off vendor-specific BENCHLING schemas ## Code Changes **Parser file**: Updated model and mapper imports from `benchling._2023._09` → `rec._2025._03` **Structure file**: - Updated schema mapper imports - Added two new required `Metadata` fields: `asm_file_identifier` and `data_system_instance_id` - Moved `analytical_method_identifier` and `experimental_data_identifier` from `MeasurementGroup` to individual `Measurement` instances (per REC/2025/03 schema structure) ## JSON Output Changes All measurement data values are preserved identically. Structural changes: | Change | Details | |--------|---------| | Manifest URL | `BENCHLING/2023/09` → `REC/2025/03` | | New fields | `ASM file identifier`, `data system instance identifier` (N/A) | | Field moves | `analytical method identifier` and `experimental data identifier` moved from `measurement aggregate document` to each `measurement document` item | | Field ordering | Some fields reordered within objects (cosmetic, different model field order) | **Fields deleted in test data:** - `root['plate reader aggregate document']['plate reader document'][0]['measurement aggregate document']['analytical method identifier']` - `root['plate reader aggregate document']['plate reader document'][0]['measurement aggregate document']['experimental data identifier']` (These fields moved to individual measurement documents, not actually lost) ## Migration Status (Plate Reader BENCHLING Parsers) | Parser | Status | Reason | |--------|--------|--------| | example_weyland_yutani | **This PR** | FLUORESCENCE only — clean migration | | mabtech_apex | Blocked | OPTICAL_IMAGING only — type removed from REC | | agilent_gen5_image | Blocked | OPTICAL_IMAGING only — type removed from REC | | ctl_immunospot | Blocked | OPTICAL_IMAGING only — type removed from REC | | revvity_kaleido | Blocked | Mixed types including OPTICAL_IMAGING | ## Test plan - [x] `pytest tests/parsers/example_weyland_yutani/ --force-overwrite` — 2/2 pass - [x] Full lint (ruff + black + mypy) — clean - [x] Pre-push hook — 547/547 tests pass 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 1ed899d commit fa55d5d

4 files changed

Lines changed: 198 additions & 130 deletions

File tree

src/allotropy/parsers/example_weyland_yutani/example_weyland_yutani_parser.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
from allotropy.allotrope.models.adm.plate_reader.benchling._2023._09.plate_reader import (
1+
from allotropy.allotrope.models.adm.plate_reader.rec._2025._03.plate_reader import (
22
Model,
33
)
4-
from allotropy.allotrope.schema_mappers.adm.plate_reader.benchling._2023._09.plate_reader import (
4+
from allotropy.allotrope.schema_mappers.adm.plate_reader.rec._2025._03.plate_reader import (
55
Data,
66
Mapper,
77
)

src/allotropy/parsers/example_weyland_yutani/example_weyland_yutani_structure.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@
55

66
import pandas as pd
77

8-
from allotropy.allotrope.schema_mappers.adm.plate_reader.benchling._2023._09.plate_reader import (
8+
from allotropy.allotrope.schema_mappers.adm.plate_reader.rec._2025._03.plate_reader import (
99
Measurement,
1010
MeasurementGroup,
1111
MeasurementType,
1212
Metadata,
1313
)
1414
from allotropy.exceptions import AllotropeConversionError
15+
from allotropy.parsers.constants import NOT_APPLICABLE
1516
from allotropy.parsers.example_weyland_yutani import constants
1617
from allotropy.parsers.utils.uuids import random_uuid_str
1718

@@ -88,8 +89,11 @@ def create(df: pd.DataFrame | None) -> list[Plate]:
8889

8990

9091
def create_metadata(instrument: Instrument, file_path: str) -> Metadata:
92+
path = Path(file_path)
9193
return Metadata(
92-
file_name=Path(file_path).name,
94+
asm_file_identifier=path.with_suffix(".json").name,
95+
data_system_instance_id=NOT_APPLICABLE,
96+
file_name=path.name,
9397
unc_path=file_path,
9498
model_number=instrument.serial_number,
9599
device_identifier=instrument.nickname,
@@ -101,8 +105,6 @@ def create_measurement_group(
101105
) -> MeasurementGroup:
102106
return MeasurementGroup(
103107
plate_well_count=plate.number_of_wells,
104-
analytical_method_identifier=basic_assay_info.protocol_id,
105-
experimental_data_identifier=basic_assay_info.assay_id,
106108
# TODO(tutorial): extract and return actual measurement time
107109
measurement_time="2022-12-31",
108110
measurements=[
@@ -114,6 +116,8 @@ def create_measurement_group(
114116
sample_identifier=f"Plate {plate.number}",
115117
location_identifier=f"{result.col}{result.row}",
116118
fluorescence=result.value,
119+
analytical_method_identifier=basic_assay_info.protocol_id,
120+
experimental_data_identifier=basic_assay_info.assay_id,
117121
)
118122
for result in plate.results
119123
],

0 commit comments

Comments
 (0)