Skip to content
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

feat(shared-data): properly load new pipette configurations from shared data #11795

Conversation

Laura-Danielle
Copy link
Contributor

Overview

We have a completely new shape for pipette configurations that need to be loaded in. Loading in major and minor versions for pipettes will be addressed in a fast follow-up (and also changes required for the xfail test here). I wanted to avoid making the diff confusing by making changes to the json again.

The hope for this refactor is that ot3_pipette_config.py will replace pipette_config.py once we can support OT2 pipettes in this new configuration format.

Changelog

  • Added pydantic models in shared data to actually load the definition into
  • Added dataclasses in the python api side to handle loading an OT3PipetteConfiguration model.

To-Do in follow-ups

  • support major/minor version
  • add in better support for the sensor key (tbd on what this looks like and is low priority)

Review requests

Does this look OK? Missing doc strings/tests etc?

Risk assessment

Low. Still not being used in the hardware controller yet. That is for a follow-up PR.

…ed data

We have a completely new shape for pipette configurations that need to be loaded in.
@Laura-Danielle Laura-Danielle requested a review from a team November 30, 2022 18:31
@Laura-Danielle Laura-Danielle requested a review from a team as a code owner November 30, 2022 18:31
@codecov
Copy link

codecov bot commented Nov 30, 2022

Codecov Report

Merging #11795 (b2a4bb1) into RLIQ-131-support-96-channel (352fdfd) will increase coverage by 0.04%.
The diff coverage is 100.00%.

Impacted file tree graph

@@                       Coverage Diff                       @@
##           RLIQ-131-support-96-channel   #11795      +/-   ##
===============================================================
+ Coverage                        74.14%   74.19%   +0.04%     
===============================================================
  Files                             2106     2108       +2     
  Lines                            58491    58603     +112     
  Branches                          6218     6218              
===============================================================
+ Hits                             43371    43483     +112     
  Misses                           13654    13654              
  Partials                          1466     1466              
Flag Coverage Δ
app 72.60% <ø> (ø)
notify-server 88.26% <ø> (ø)
protocol-designer 45.86% <ø> (ø)
shared-data 86.07% <100.00%> (+1.26%) ⬆️
step-generation 88.46% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
.../python/opentrons_shared_data/pipette/load_data.py 100.00% <100.00%> (ø)
...pentrons_shared_data/pipette/pipette_definition.py 100.00% <100.00%> (ø)

Copy link
Member

@sfoster1 sfoster1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks pretty good, but why have both the pydantic definitions and the dataclass definitions?


@dataclass(frozen=True)
class OT2PipetteConfigurations(SharedPipetteConfigurations):
tip_length: float # TODO(seth): remove
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hey wait why are you dragging me into this?!?!?!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LOL the comment is still relevant!

@Laura-Danielle
Copy link
Contributor Author

We tend to stick to using dataclasses (and pythonic snake case) in the hardware controller + objects used in the hardware controller.

That's the main reason I'm loading in the pydantic model and then reformatting to a dataclass.

Copy link
Contributor

@mcous mcous left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditching the Pydantic / dataclass duplication is great. Doesn't look like config loading is working, though, because the PipetteModelType enum values match the directory paths rather than the JSON values

Comment on lines 1 to 8
from typing_extensions import Literal

PLUNGER_CURRENT_MINIMUM = 0.1
PLUNGER_CURRENT_MAXIMUM = 1.5


PipetteModelMajorVersion = Literal[1]
PipetteModelMinorVersion = Literal[0, 1, 2, 3]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've personally soured on the idea of a constants.py / constants.ts file in modules; it just makes things harder to find IMO. Could any of these things move elsewhere?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can move it into the pipette_definition file for now. I had created this file with the intention of sticking random things like 'quirks' and 'mutable_configs' in here that are only relevant for OT2 pipettes. I could probably call that file a different name at that point in time.

shared-data/python/opentrons_shared_data/pipette/types.py Outdated Show resolved Hide resolved
Copy link
Contributor

@mcous mcous left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! Continuing the testing conversation from the previous PR; implementation details are still leaking into the configuration loading test

load_shared_data("pipette/definitions/2/general/single_channel/p50/1_0.json")
)

assert pipette_config.channels.as_int == general["channels"]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think calling load_shared_data inside the test muddies the test. I think we should either have:

  1. An integration test, that knows nothing about how the pipette configuration files are stored
    • Value of this test: test that the unit probably works
    • Non-value: this test would provide no design feedback to unit internals
    • How to get there: replace the expected values with hardcoded literals in the test
  2. A collaborator test:
    • Value of this test: design feedback for unit internals and that the unit is wired up to other units as we expect
    • Non-value: this test would not validate that the unit works, due to the use of mocks
    • How to get there: stub out load_shared_data, check that it's called with the correct path

What's currently written tries to split the difference between (1) and (2), which ends up compromising both and causing other problems (like tests failing for unclear reasons if/when we change things).

Given this unit's role, I would recommend option (1)

@Laura-Danielle Laura-Danielle merged commit e59f558 into RLIQ-131-support-96-channel Dec 1, 2022
@Laura-Danielle Laura-Danielle deleted the RLIQ-251-v2-pipette-configuration-loading branch December 1, 2022 22:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants