-
Notifications
You must be signed in to change notification settings - Fork 178
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(robot-server): Fix error parsing persisted loadModule commands #14509
fix(robot-server): Fix error parsing persisted loadModule commands #14509
Conversation
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## chore_release-7.2.0 #14509 +/- ##
=======================================================
+ Coverage 67.74% 67.76% +0.02%
=======================================================
Files 2517 2517
Lines 72068 72119 +51
Branches 9278 9278
=======================================================
+ Hits 48823 48873 +50
- Misses 21027 21028 +1
Partials 2218 2218
Flags with carried forward coverage won't be shown. Click here to find out more.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah that looks like a good fix.
I suspect that the safest thing here is to always always always load input from storage, any storage, in a way that treats null
and not present
as exactly equivalent.
# Overview Add protocols pulled from v7.2.0 pull requests for Analysis Snapshot testing. All work filed under [RQA-2434](https://opentrons.atlassian.net/browse/RQA-2434) # Test Plan - [x] Add partial tip pickup protocols from Sanitti - [x] Add ABR protocol from [RABR-23](https://opentrons.atlassian.net/browse/RABR-23) - [x] Run new protocols locally and verify results - [x] Run in workflow dispatch action and verify success [[link]](https://github.com/Opentrons/opentrons/actions/runs/8160792870/job/22308167177) # Changelog Here are the protocols added and where I found them: - [RQA-2098](https://opentrons.atlassian.net/browse/RQA-2098) - Flex_P1000_96_Gripper_TC_TM_HS_AnalysisError_GripperCollisionWithTips.json - #14491 - Flex_None_None_TC_2_14_verifyThermocyclerLoadedSlots.py - Flex_None_None_TC_2_15_verifyThermocyclerLoadedSlots.py - Flex_None_None_TC_2_16_verifyThermocyclerLoadedSlots.py - Flex_None_None_TC_2_17_verifyThermocyclerLoadedSlots.py - OT2_None_None_TC_2_14_VerifyThermocyclerLoadedSlots.py - OT2_None_None_TC_2_15_VerifyThermocyclerLoadedSlots.py - OT2_None_None_TC_2_16_VerifyThermocyclerLoadedSlots.py - OT2_None_None_TC_2_17_VerifyThermocyclerLoadedSlots.py - #14475 - Flex_None_None_TC_2_16_AnalysisError_TrashBinAndThermocyclerConflict.py - OT2_None_None_2_16_verifyDoesNotDeadlock.py - OT2_None_None_HS_2_16_AnalysisError_HeaterShakerConflictWithTrashBin1.py - OT2_None_None_HS_2_16_AnalysisError_HeaterShakerConflictWithTrashBin2.py - #14547 - Flex_P1000_96_None_TC_2_16_AnalysisError_pipetteCollisionWithThermocyclerLid.py - #14522 - Flex_P1000_96_None_TC_2_16_AnalysisError_pipetteCollisionWithThermocyclerLidClips.py - Dispense functionality validation - OT2_P300M_P20S_TC_HS_TM_2_15_dispense_changes.py - OT2_P300M_P20S_TC_HS_TM_2_16_dispense_changes.py - OT2_P300M_P20S_TC_HS_TM_2_17_dispense_changes.py - #14253 - OT2_P300S_None_2_16_verifyNoFloatingPointErrorInPipetting.py # Review requests There are a few pull requests that I had questions about. I will @ the people that worked on them to answer the questions - #14437 - @sfoster1, Can I use the protocol found in [RABR-23](https://opentrons.atlassian.net/browse/RABR-23) to get this to happen? Is there another way? - #14509 - @SyntaxColoring, can analysis capture this change or is this only relavant during actual protocol runtime? - #14510 - @TamarZanzouri or @SyntaxColoring, can I raise a generic python exception inside the protocol to trigger this functionality? - #14512 - @Laura-Danielle or @SyntaxColoring, Iant to validate my logic. This not a good canidate for snapshot testing because you have to run LPC and Calibration which is not taken into account during analysis. Can you confirm? # Risk assessment None [RQA-2434]: https://opentrons.atlassian.net/browse/RQA-2434?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ [RQA-2098]: https://opentrons.atlassian.net/browse/RQA-2098?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ [RABR-23]: https://opentrons.atlassian.net/browse/RABR-23?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
Add protocols pulled from v7.2.0 pull requests for Analysis Snapshot testing. All work filed under [RQA-2434](https://opentrons.atlassian.net/browse/RQA-2434) - [x] Add partial tip pickup protocols from Sanitti - [x] Add ABR protocol from [RABR-23](https://opentrons.atlassian.net/browse/RABR-23) - [x] Run new protocols locally and verify results - [x] Run in workflow dispatch action and verify success [[link]](https://github.com/Opentrons/opentrons/actions/runs/8160792870/job/22308167177) Here are the protocols added and where I found them: - [RQA-2098](https://opentrons.atlassian.net/browse/RQA-2098) - Flex_P1000_96_Gripper_TC_TM_HS_AnalysisError_GripperCollisionWithTips.json - #14491 - Flex_None_None_TC_2_14_verifyThermocyclerLoadedSlots.py - Flex_None_None_TC_2_15_verifyThermocyclerLoadedSlots.py - Flex_None_None_TC_2_16_verifyThermocyclerLoadedSlots.py - Flex_None_None_TC_2_17_verifyThermocyclerLoadedSlots.py - OT2_None_None_TC_2_14_VerifyThermocyclerLoadedSlots.py - OT2_None_None_TC_2_15_VerifyThermocyclerLoadedSlots.py - OT2_None_None_TC_2_16_VerifyThermocyclerLoadedSlots.py - OT2_None_None_TC_2_17_VerifyThermocyclerLoadedSlots.py - #14475 - Flex_None_None_TC_2_16_AnalysisError_TrashBinAndThermocyclerConflict.py - OT2_None_None_2_16_verifyDoesNotDeadlock.py - OT2_None_None_HS_2_16_AnalysisError_HeaterShakerConflictWithTrashBin1.py - OT2_None_None_HS_2_16_AnalysisError_HeaterShakerConflictWithTrashBin2.py - #14547 - Flex_P1000_96_None_TC_2_16_AnalysisError_pipetteCollisionWithThermocyclerLid.py - #14522 - Flex_P1000_96_None_TC_2_16_AnalysisError_pipetteCollisionWithThermocyclerLidClips.py - Dispense functionality validation - OT2_P300M_P20S_TC_HS_TM_2_15_dispense_changes.py - OT2_P300M_P20S_TC_HS_TM_2_16_dispense_changes.py - OT2_P300M_P20S_TC_HS_TM_2_17_dispense_changes.py - #14253 - OT2_P300S_None_2_16_verifyNoFloatingPointErrorInPipetting.py There are a few pull requests that I had questions about. I will @ the people that worked on them to answer the questions - #14437 - @sfoster1, Can I use the protocol found in [RABR-23](https://opentrons.atlassian.net/browse/RABR-23) to get this to happen? Is there another way? - #14509 - @SyntaxColoring, can analysis capture this change or is this only relavant during actual protocol runtime? - #14510 - @TamarZanzouri or @SyntaxColoring, can I raise a generic python exception inside the protocol to trigger this functionality? - #14512 - @Laura-Danielle or @SyntaxColoring, Iant to validate my logic. This not a good canidate for snapshot testing because you have to run LPC and Calibration which is not taken into account during analysis. Can you confirm? None [RQA-2434]: https://opentrons.atlassian.net/browse/RQA-2434?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ [RQA-2098]: https://opentrons.atlassian.net/browse/RQA-2098?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ [RABR-23]: https://opentrons.atlassian.net/browse/RABR-23?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
Add protocols pulled from v7.2.0 pull requests for Analysis Snapshot testing. All work filed under [RQA-2434](https://opentrons.atlassian.net/browse/RQA-2434) - [x] Add partial tip pickup protocols from Sanitti - [x] Add ABR protocol from [RABR-23](https://opentrons.atlassian.net/browse/RABR-23) - [x] Run new protocols locally and verify results - [x] Run in workflow dispatch action and verify success [[link]](https://github.com/Opentrons/opentrons/actions/runs/8160792870/job/22308167177) Here are the protocols added and where I found them: - [RQA-2098](https://opentrons.atlassian.net/browse/RQA-2098) - Flex_P1000_96_Gripper_TC_TM_HS_AnalysisError_GripperCollisionWithTips.json - #14491 - Flex_None_None_TC_2_14_verifyThermocyclerLoadedSlots.py - Flex_None_None_TC_2_15_verifyThermocyclerLoadedSlots.py - Flex_None_None_TC_2_16_verifyThermocyclerLoadedSlots.py - Flex_None_None_TC_2_17_verifyThermocyclerLoadedSlots.py - OT2_None_None_TC_2_14_VerifyThermocyclerLoadedSlots.py - OT2_None_None_TC_2_15_VerifyThermocyclerLoadedSlots.py - OT2_None_None_TC_2_16_VerifyThermocyclerLoadedSlots.py - OT2_None_None_TC_2_17_VerifyThermocyclerLoadedSlots.py - #14475 - Flex_None_None_TC_2_16_AnalysisError_TrashBinAndThermocyclerConflict.py - OT2_None_None_2_16_verifyDoesNotDeadlock.py - OT2_None_None_HS_2_16_AnalysisError_HeaterShakerConflictWithTrashBin1.py - OT2_None_None_HS_2_16_AnalysisError_HeaterShakerConflictWithTrashBin2.py - #14547 - Flex_P1000_96_None_TC_2_16_AnalysisError_pipetteCollisionWithThermocyclerLid.py - #14522 - Flex_P1000_96_None_TC_2_16_AnalysisError_pipetteCollisionWithThermocyclerLidClips.py - Dispense functionality validation - OT2_P300M_P20S_TC_HS_TM_2_15_dispense_changes.py - OT2_P300M_P20S_TC_HS_TM_2_16_dispense_changes.py - OT2_P300M_P20S_TC_HS_TM_2_17_dispense_changes.py - #14253 - OT2_P300S_None_2_16_verifyNoFloatingPointErrorInPipetting.py There are a few pull requests that I had questions about. I will @ the people that worked on them to answer the questions - #14437 - @sfoster1, Can I use the protocol found in [RABR-23](https://opentrons.atlassian.net/browse/RABR-23) to get this to happen? Is there another way? - #14509 - @SyntaxColoring, can analysis capture this change or is this only relavant during actual protocol runtime? - #14510 - @TamarZanzouri or @SyntaxColoring, can I raise a generic python exception inside the protocol to trigger this functionality? - #14512 - @Laura-Danielle or @SyntaxColoring, Iant to validate my logic. This not a good canidate for snapshot testing because you have to run LPC and Calibration which is not taken into account during analysis. Can you confirm? None [RQA-2434]: https://opentrons.atlassian.net/browse/RQA-2434?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ [RQA-2098]: https://opentrons.atlassian.net/browse/RQA-2098?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ [RABR-23]: https://opentrons.atlassian.net/browse/RABR-23?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
Overview
Fixes RSS-471.
Test Plan
The integration tests added in #14508 will cover this.
Details
When you load a Magnetic Block, that's represented by a Protocol Engine
loadModule
command. Unlike otherloadModule
commands, it will not have aresult.serialNumber
. This is all good and correct so far.That
serialNumber
field is defined like this:This means, when parsing this model from persistent storage,
serialNumber
must be present, either as a string or as an explicit PythonNone
/ JSONnull
. It cannot be omitted; it will not default toNone
/null
.The bug is that this does not match how these models are saved to persistent storage. There, the field is omitted. My fix is to add a default of
None
, so they match.We're only seeing this now because, as of #14355, we're parsing models that were saved under a different set of Pydantic options. Formerly, we were doing
.dict()
(for analyses, runs, and commands). Now, we're doing.json(by_alias=True
,exclude_none=True
) (for analyses, runs, and commands). The "bad" part of that isexclude_none=True
—see below.Review requests
Is this the only place we've introduced this bug?
Theoretically, this bug can happen in any other model that's declaring a field like
field: Optional[T] = Field(default=...)
.I've run a global text search on the monorepo with this Comby rule. Basically, look for any
Optional[X] = Field(Y)
, whereY
contains...
.Although there are many hits, all except for this one seem to be false positives or models that aren't stored in the database.
But it's difficult to be confident that this search is exhaustive.
Is
exclude_none=True
a correct way to serialize these objects in the first place?This seems like it will take a bit of attention to untangle, but here is a spike ticket for us to figure that out: RSS-473. If you have any thoughts, drop them there.
Risk assessment
I don't think this change can make anything worse, but the underlying hazard still remains.