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(robot-server, api): accept RTP overrides via /protocols and inject them in python executor #14688

Merged

Conversation

sanni-t
Copy link
Member

@sanni-t sanni-t commented Mar 19, 2024

Closes AUTH-64, AUTH-65

Overview

Updates the POST /protocols API to accept an additional runTimeParameterValues form-data field. This field is expected to be a stringified JSON composed of key-value pairs of the parameter variable name and its override value.

These override values are converted into a dictionary and passed into the protocol runner, which makes them available to the python executor.

Test Plan

  • Send a POST protocol request and verify that an analysis is created
  • POST the same protocol again and verify that the response still gives the same analysis & protocol IDs
  • Send a protocol with runTimeParameterValues in request data and verify the request goes through, and a new analysis is created on the same protocol ID

Known issues

  • every time a protocol creation request contains a non-empty runTimeParameterValues data, analysis is triggered, regardless of whether we have previously analyzed protocols with the same param values
  • if no param values are sent with an existing protocol, a new analysis is NOT triggered, regardless of whether the previous analyses were done using any RTP values or not

These will be addressed in AUTH-70

Review requests

  • check for usual code sanity

Risk assessment

High. Affects the correctness of order and contents of analysis summaries returned by the POST /protocols endpoint when using run time parameters. This behavior will remain broken until AUTH-70 is implemented. Until then, please be cautious that a protocol analysis request that uses custom RTP values will modify an existing protocol analysis database such that the app might pick the wrong analysis for a run. I will recommend deleting such protocols (and runs) from the database after you are done testing, especially if you are testing on a shared robot.

Copy link

codecov bot commented Mar 19, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 67.33%. Comparing base (6695f9e) to head (32011f8).
Report is 43 commits behind head on edge.

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##             edge   #14688   +/-   ##
=======================================
  Coverage   67.33%   67.33%           
=======================================
  Files        2485     2485           
  Lines       71386    71386           
  Branches     9030     9030           
=======================================
  Hits        48069    48069           
  Misses      21173    21173           
  Partials     2144     2144           
Flag Coverage Δ
g-code-testing 92.43% <ø> (ø)

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

Files Coverage Δ
api/src/opentrons/execute.py 54.23% <ø> (ø)
api/src/opentrons/protocol_engine/types.py 97.50% <ø> (ø)
...i/src/opentrons/protocol_reader/protocol_reader.py 100.00% <ø> (ø)
...i/src/opentrons/protocol_runner/legacy_wrappers.py 100.00% <ø> (ø)
...i/src/opentrons/protocol_runner/protocol_runner.py 100.00% <ø> (ø)
api/src/opentrons/protocols/execution/execute.py 90.90% <ø> (ø)
api/src/opentrons/simulate.py 57.73% <ø> (ø)
...ot-server/robot_server/protocols/analysis_store.py 100.00% <ø> (ø)
...server/robot_server/protocols/protocol_analyzer.py 100.00% <ø> (ø)
robot-server/robot_server/protocols/router.py 100.00% <ø> (ø)
... and 1 more

Comment on lines 230 to 239
task_runner.run(
protocol_analyzer.analyze,
protocol_resource=resource,
analysis_id=analysis_id,
run_time_param_overrides=parsed_rtp,
)
analysis_store.add_pending(
protocol_id=cached_protocol_id,
analysis_id=analysis_id,
)
Copy link
Contributor

Choose a reason for hiding this comment

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

This will probably need to be implemented in a different PR, but at some point before releasing this, we'll need to cap the maximum number of protocol analyses. I'm curious if you have any thoughts on what the limit will be?

Copy link
Member Author

Choose a reason for hiding this comment

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

Ya, we'll have to figure that out. How did we land on the max number of protocols and runs to store? Is there a hard cut off for memory availability we need to keep in mind?

Copy link
Contributor

Choose a reason for hiding this comment

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

It's mostly how long it would take to parse them all into Pydantic models if we had to do some kind of migration.

@sanni-t sanni-t marked this pull request as ready for review March 20, 2024 16:28
@sanni-t sanni-t requested review from a team as code owners March 20, 2024 16:28
@sanni-t sanni-t requested review from a team and removed request for a team March 20, 2024 16:28
Copy link
Contributor

@jbleon95 jbleon95 left a comment

Choose a reason for hiding this comment

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

Some small style nitpicks but otherwise LGTM!

def run_protocol(
protocol: Protocol,
context: ProtocolContext,
run_time_param_overrides: Optional[Dict[str, Union[float, bool, str]]] = None,
Copy link
Contributor

Choose a reason for hiding this comment

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

We should use the PE type here if possible

Copy link
Member Author

Choose a reason for hiding this comment

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

I had a TODO for this exact thing. I/ pycharm must have removed it during refactor. Putting it back in.

@@ -184,6 +189,7 @@ async def create_protocol(
Arguments:
files: List of uploaded files, from form-data.
key: Optional key for client-side tracking
runTimeParameterValues: Key value pairs of run-time parameters defined in a protocol.
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's make this snake_case for consistency

Copy link
Member Author

Choose a reason for hiding this comment

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

It's actually camel case for robot-server HTTP API consistency purposes.

Copy link
Contributor

@SyntaxColoring SyntaxColoring left a comment

Choose a reason for hiding this comment

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

hype

Comment on lines 169 to 172
runTimeParameterValues: Optional[str] = Form(
default=None,
description="Key value pairs of run-time parameters defined in a protocol.",
),
Copy link
Contributor

Choose a reason for hiding this comment

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

It might be worth clarifying in this description that:

  • This is a string holding a JSON object.
  • This affects the auto-started analysis resource (GET /protocols/{id}/analyses/{id}).

Comment on lines 98 to 101
save:
json:
protocol_id: data.id
analysis_id: data.analysisSummaries[1].id
Copy link
Contributor

Choose a reason for hiding this comment

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

Looks like this is unused.

Suggested change
save:
json:
protocol_id: data.id
analysis_id: data.analysisSummaries[1].id

# We have to do this isinstance check because if `runTimeParameterValues` is
# not specified in the request, then it gets assigned a Form(None) value
# instead of just a None. \(O.o)/
parsed_rtp = json.loads(runTimeParameterValues)
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit, doesn't have to happen in this PR: This will raise a 500 error if the client passes invalid JSON. Ideally, it would return a 422 instead. I wonder if there's a way to make a custom "run-time parameter multipart form field" Pydantic type so FastAPI can do that for us.

Copy link
Member Author

Choose a reason for hiding this comment

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

Hmm.. interesting idea. I'll add a TODO

@sanni-t sanni-t merged commit fce980f into edge Mar 20, 2024
22 checks passed
@sanni-t sanni-t deleted the AUTH-64-protocols-endpoint-to-accept-runtime-parameter-values branch March 20, 2024 21:14
sanni-t added a commit that referenced this pull request Apr 3, 2024
Closes AUTH-229

# Overview

Updates the `/protocols` endpoints to always maintain the order of list
of analyses as most-recently-started-analysis last, making sure to
verify if a new analysis needs to be triggered because of new
run-time-parameter values for a previously uploaded protocol.

# Risk assessment

Medium. Does database update and fixes the analysis order that was
broken by #14688

---------

Co-authored-by: Max Marrone <[email protected]>
Carlos-fernandez pushed a commit that referenced this pull request May 20, 2024
…ct them in python executor (#14688)

Closes AUTH-64, AUTH-65

Updates the POST /protocols API to accept an additional runTimeParameterValues form-data field. This field is expected to be a stringified JSON composed of key-value pairs of the parameter variable name and its override value.

These override values are converted into a dictionary and passed into the protocol runner, which makes them available to the python executor.

Risk assessment:

High. Affects the correctness of order and contents of analysis summaries returned by the POST /protocols endpoint when using run time parameters. This behavior will remain broken until AUTH-70 is implemented. Until then, please be cautious that a protocol analysis request that uses custom RTP values will modify an existing protocol analysis database such that the app might pick the wrong analysis for a run. I will recommend deleting such protocols (and runs) from the database after you are done testing, especially if you are testing on a shared robot.
Carlos-fernandez pushed a commit that referenced this pull request May 20, 2024
Closes AUTH-229

# Overview

Updates the `/protocols` endpoints to always maintain the order of list
of analyses as most-recently-started-analysis last, making sure to
verify if a new analysis needs to be triggered because of new
run-time-parameter values for a previously uploaded protocol.

# Risk assessment

Medium. Does database update and fixes the analysis order that was
broken by #14688

---------

Co-authored-by: Max Marrone <[email protected]>
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