Skip to content

Commit

Permalink
fix(app): Tolerate old tip length calibration records without a uri
Browse files Browse the repository at this point in the history
… field (#14622)
  • Loading branch information
SyntaxColoring committed Mar 11, 2024
1 parent 5090243 commit 3dfbb6f
Show file tree
Hide file tree
Showing 8 changed files with 73 additions and 26 deletions.
4 changes: 2 additions & 2 deletions api/src/opentrons/calibration_storage/ot2/deck_attitude.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ def get_robot_deck_attitude() -> Optional[v1.DeckCalibrationModel]:
pass
except (json.JSONDecodeError, ValidationError):
log.warning(
"Deck calibration is malformed. Please factory reset your calibrations."
"Deck calibration is malformed. Please factory reset your calibrations.",
exc_info=True,
)
pass
return None
3 changes: 2 additions & 1 deletion api/src/opentrons/calibration_storage/ot2/pipette_offset.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,8 @@ def get_pipette_offset(
return None
except (json.JSONDecodeError, ValidationError):
log.warning(
f"Malformed calibrations for {pipette_id} on {mount}. Please factory reset your calibrations."
f"Malformed calibrations for {pipette_id} on {mount}. Please factory reset your calibrations.",
exc_info=True,
)
# TODO: Delete the bad calibration here maybe?
return None
Expand Down
49 changes: 32 additions & 17 deletions api/src/opentrons/calibration_storage/ot2/tip_length.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,28 +37,43 @@ def _convert_tip_length_model_to_dict(
def tip_lengths_for_pipette(
pipette_id: str,
) -> typing.Dict[LabwareUri, v1.TipLengthModel]:
tip_lengths = {}
try:
tip_length_filepath = config.get_tip_length_cal_path() / f"{pipette_id}.json"
all_tip_lengths_for_pipette = io.read_cal_file(tip_length_filepath)
for tiprack_identifier, data in all_tip_lengths_for_pipette.items():
# We normally key these calibrations by their tip rack URI,
# but older software had them keyed by their tip rack hash.
# Migrate from the old format, if necessary.
if "/" not in tiprack_identifier:
data["definitionHash"] = tiprack_identifier
tiprack_identifier = data.pop("uri")
try:
tip_lengths[LabwareUri(tiprack_identifier)] = v1.TipLengthModel(**data)
except (json.JSONDecodeError, ValidationError):
log.warning(
f"Tip length calibration is malformed for {tiprack_identifier} on {pipette_id}"
)
pass
return tip_lengths
except FileNotFoundError:
log.debug(f"Tip length calibrations not found for {pipette_id}")
return tip_lengths
return {}
except json.JSONDecodeError:
log.warning(
f"Tip length calibration is malformed for {pipette_id}", exc_info=True
)
return {}

tip_lengths: typing.Dict[LabwareUri, v1.TipLengthModel] = {}

for tiprack_identifier, data in all_tip_lengths_for_pipette.items():
# We normally key these calibrations by their tip rack URI,
# but older software had them keyed by their tip rack hash.
# Migrate from the old format, if necessary.
tiprack_identifier_is_uri = "/" in tiprack_identifier
if not tiprack_identifier_is_uri:
data["definitionHash"] = tiprack_identifier
uri = data.pop("uri", None)
if uri is None:
# We don't have a way to migrate old records without a URI,
# so skip over them.
continue
else:
tiprack_identifier = uri

try:
tip_lengths[LabwareUri(tiprack_identifier)] = v1.TipLengthModel(**data)
except ValidationError:
log.warning(
f"Tip length calibration is malformed for {tiprack_identifier} on {pipette_id}",
exc_info=True,
)
return tip_lengths


def load_tip_length_calibration(
Expand Down
4 changes: 2 additions & 2 deletions api/src/opentrons/calibration_storage/ot3/deck_attitude.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def get_robot_belt_attitude() -> Optional[v1.BeltCalibrationModel]:
pass
except (json.JSONDecodeError, ValidationError):
log.warning(
"Belt calibration is malformed. Please factory reset your calibrations."
"Belt calibration is malformed. Please factory reset your calibrations.",
exc_info=True,
)
pass
return None
6 changes: 4 additions & 2 deletions api/src/opentrons/calibration_storage/ot3/module_offset.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,8 @@ def get_module_offset(
return None
except (json.JSONDecodeError, ValidationError):
log.warning(
f"Malformed calibrations for {module_id} on slot {slot}. Please factory reset your calibrations."
f"Malformed calibrations for {module_id} on slot {slot}. Please factory reset your calibrations.",
exc_info=True,
)
return None

Expand All @@ -130,7 +131,8 @@ def load_all_module_offsets() -> List[v1.ModuleOffsetModel]:
)
except (json.JSONDecodeError, ValidationError):
log.warning(
f"Malformed module calibrations for {file}. Please factory reset your calibrations."
f"Malformed module calibrations for {file}. Please factory reset your calibrations.",
exc_info=True,
)
continue
return calibrations
3 changes: 2 additions & 1 deletion api/src/opentrons/calibration_storage/ot3/pipette_offset.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ def get_pipette_offset(
return None
except (json.JSONDecodeError, ValidationError):
log.warning(
f"Malformed calibrations for {pipette_id} on {mount}. Please factory reset your calibrations."
f"Malformed calibrations for {pipette_id} on {mount}. Please factory reset your calibrations.",
exc_info=True,
)
return None
2 changes: 1 addition & 1 deletion api/src/opentrons/config/robot_configs.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ def _load_json(filename: Union[str, Path]) -> Dict[str, Any]:
log.warning("{0} not found. Loading defaults".format(filename))
res = {}
except json.decoder.JSONDecodeError:
log.warning("{0} is corrupt. Loading defaults".format(filename))
log.warning("{0} is corrupt. Loading defaults".format(filename), exc_info=True)
res = {}
return cast(Dict[str, Any], res)

Expand Down
28 changes: 28 additions & 0 deletions api/tests/opentrons/calibration_storage/test_tip_length_ot2.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,31 @@ def test_delete_all_tip_calibration(starting_calibration_data: Any) -> None:
clear_tip_length_calibration()
assert tip_lengths_for_pipette("pip1") == {}
assert tip_lengths_for_pipette("pip2") == {}


def test_uriless_calibrations_are_dropped(ot_config_tempdir: object) -> None:
"""Legacy records without a `uri` field should be silently ignored."""

data = {
"ed323db6ca1ddf197aeb20667c1a7a91c89cfb2f931f45079d483928da056812": {
"tipLength": 123,
"lastModified": "2021-01-11T00:34:29.291073+00:00",
"source": "user",
"status": {"markedBad": False},
},
"130e17bb7b2f0c0472dcc01c1ff6f600ca1a6f9f86a90982df56c4bf43776824": {
"tipLength": 456,
"lastModified": "2021-05-12T22:16:14.249567+00:00",
"source": "user",
"status": {"markedBad": False},
"uri": "opentrons/opentrons_96_filtertiprack_200ul/1",
},
}

io.save_to_file(config.get_tip_length_cal_path(), "pipette1234", data)
result = tip_lengths_for_pipette("pipette1234")
assert len(result) == 1
assert (
result[LabwareUri("opentrons/opentrons_96_filtertiprack_200ul/1")].tipLength
== 456
)

0 comments on commit 3dfbb6f

Please sign in to comment.